为什么"git fetch origin branch:branch"仅适用于非当前分支?

MaD*_*aDa 12 git

在处理功能分支时,我使用此Git命令将我的"develop"分支更新为最新状态,在将我的功能分支与"develop"合并之前:

git fetch origin develop:develop
Run Code Online (Sandbox Code Playgroud)

这是有效的,即本地"开发"指向与"原点/开发"相同的提交,并且处于最新的起源状态.

不知何故,当检查"develop"分支时,此命令失败:

fatal: Refusing to fetch into current branch refs/heads/develop of non-bare repository
fatal: The remote end hung up unexpectedly
Run Code Online (Sandbox Code Playgroud)

如果我知道为什么会发生这种情况,那将有助于我更好地理解Git.

Von*_*onC 16

错误消息来自builtin/fetch.c#check_not_current_branch().
该功能一直回到8ee5d73,2008年10月,git 1.6.0.4

评论很有​​启发性:

一些令人困惑的教程表明,以这样的方式获取当前分支是个好主意:

git fetch origin master:master
Run Code Online (Sandbox Code Playgroud)

(或者更糟糕的是:使用"pull"而不是"fetch"的相同命令行).
虽然存储你想要的内容可能是有意义的,但当前分支是" master" 时通常是完全错误的.
只有当(不正确的)" git pull origin master:master"尝试通过给予--update-head-ok底层" git fetch" 来解决时才允许这样做,否则我们应该拒绝它,但是在某些地方我们就失去了这种行为.

现在,对当前分支的检查在非裸存储库中执行,这是对原始行为的改进.

考虑到函数check_not_current_branch()调用:

if (!update_head_ok)
        check_not_current_branch(ref_map);
Run Code Online (Sandbox Code Playgroud)

这意味着git fetch -u origin develop:develop应该工作.

-u
--update-head-ok
Run Code Online (Sandbox Code Playgroud)

默认情况下,git fetch拒绝更新与当前分支对应的头部.此标志禁用检查.
这纯粹是为了与内部git pull沟通git fetch,除非你实施自己的瓷器,否则你不应该使用它.

即使您不应该使用该选项,它也会回答您的初始要求,使" git fetch origin branch:branch"在当前分支上工作.


关于这个补丁的来源,请按照那里的讨论.

虽然存储你想要的东西可能是有意义的

这是fetch部分:它存储更新的远程历史记录origin/master.
但是,当前的本地分支也是如此master.
正如这个答案中提到的:

我认为" git fetch url side:master" master当前分支何时被忽略--update-head-ok.
测试在当前失败master.

它也无法更新工作目录,并且会将索引保留为删除所有内容.


请参阅" git pull使用refspec "作为示例.
torek展示了一个例子:

假设我用git取并在两个新的提交,我将标签带来的CD.
C的父母是A,而且D是以前的节点B:

             C
            /
...--o--o--A   <-- master
            \
             o--B   <-- develop
              \
               D
Run Code Online (Sandbox Code Playgroud)

这个git fetch的输出会将其列为:

  aaaaaaa..ccccccc  master     -> origin/master
+ bbbbbbb...ddddddd develop    -> origin/develop  (forced update)
Run Code Online (Sandbox Code Playgroud)

如果您当前的分支不是, 那么强制更新可能就是您想要的develop.
但是如果你 develop键入时打开git fetch origin develop:develop,并且如果允许获取更新HEAD,那么...那么你当前的索引会反映出来D,而不再是B.
因此git diff,在您的工作树中完成将显示您的文件之间的差异D,而不是之前的HEAD B.

这很糟糕,因为您的初始git checkout develop创建了一个与BHEAD文件相同的工作树.
即使你git status是干净的(没有任何修改),如果git fetch origin develop:develop更新HEAD(强制从B更新到D),git status现在会报告在获取之前没有的差异.

这就是为什么默认情况下git fetch拒绝更新与当前分支对应的头部的原因.