我一直在玩git并坚持使用git fetch的概念。
我尝试并观察了以下情形:
1)
$ git fetch
将提取所有远程分支,并更新所有相应的远程跟踪分支。我知道它查看.git / config文件,并使用默认的远程存储库位置和默认的获取refspec,通常为“ refs / heads / :refs / remotes / origin / ”。它不会快速转发任何本地分支。
2)
$ git fetch origin
与1相同)
3)
$ git fetch origin master
仅提取master分支,并更新远程跟踪分支的原始/ master。不快进本地的“ master”分支。
4)
$ git fetch origin master:master
仅提取master分支,并更新远程跟踪分支的原始/ master。快进本地的“ master”分支。
理解1)和2)很简单。但是3)和4)使我感到困惑。
fetch命令对本地分支有什么作用?为什么它会快速转发本地分支? (证明它会影响本地分支的是我尝试git fetch origin master:master
时,检出master分支时会引发以下错误:fatal: Refusing to fetch into current branch refs/heads/master of non-bare repository
)
根据我的直觉,在任何类型的fetch命令上,更新远程跟踪分支都是默认行为。但是,执行git fetch origin master
时,它具有更新FETCH_HEAD的其他行为。执行git fetch origin master:master
时,它具有更新本地分支“ master”的其他行为。我的直觉对吗?
它会将git fetch origin master:master
解释为git fetch origin refs/heads/master:refs/heads/master
吗? (也许对我之前的问题是多余的)
它会将git fetch origin master
解释为git fetch origin refs/heads/master:
吗?
答案 0 :(得分:2)
在<refspec>
中明确提及目标时,更新匹配的本地参考 是预期的行为。
格式:
git fetch [options] <remote> <refspec>
refspec
采用以下形式
<src>:<dst>
(显然,对于“来源”和“目的地”而言)
已获取与
<src>
匹配的远程引用,并且如果<dst>
不是空字符串,则会尝试更新与之匹配的本地引用。
您还可以在此特定语法上方查看this paragraph。
并回答附带的问题:
但是,当执行
git fetch origin master
时,它具有更新FETCH_HEAD
的其他行为。执行git fetch origin master:master
时,它具有更新本地分支“ master”的其他行为。我的直觉对吗?
不完全是。如果未将<refspec>
用作<src>:<dst>
,则将给定名称用作<src>
,所以当您执行{{1 }}与git fetch origin master
相同。 git fetch origin master:master
用于内部,即FETCH_HEAD
的内部,并且可用于编写脚本,但是您不必费心每天使用git。
“它会将git
git pull
解释为fetch origin master:master
吗?(也许对我之前的问题是多余的”)
是的
它会将
git fetch origin refs/heads/master:refs/heads/master
解释为git fetch origin master
吗?
否,如果git fetch origin refs/heads/master:
的{{1}}面为空,则由于没有指向任何内容,因此没有任何更新。 (不要与上面提到的省略<dst>
本身的情况相混淆。有趣的是,相反的<refspec>
会删除:
,因为它是用void ref更新的)
答案 1 :(得分:2)
RomainValeri's answer在大多数情况下是 ,但是缺少一些项目。
首先,我们必须记下有关1.8.4之前的Git版本的特殊情况。 The 1.8.4 release notes提到
- “ git fetch origin master”不同于“ git fetch origin”或“ git fetch” 没有更新“ refs / remotes / origin / master”;这是一个早期 保持更新远程跟踪分支的设计决策 可预见的,但实际上,人们发现它的机会更多 只要有机会,就可以方便地机会性地更新它们 机会,我们在运行“ git push”时一直在更新它们 反正已经破坏了原始的“可预测性”。
因此:
git fetch origin master
在Git 1.8.3和更早版本中表现不同。在1.8.4及更高版本中,此更新refs/remotes/origin/master
(默认情况下,但取决于您的默认获取refspecs)。
对refspec的描述是正确的,但缺少一项:语法通常为:
+
的可选前导加号--force
(仅对于此特定refspec); :
;和源和目标都可以完全限定,例如refs/heads/master
,例如,不可以完全限定,例如master
。如果您使用不合格的变体,Git会找出可能的完全合格的拼写。
通常,可以省略源和目标中的任何一个(有时甚至是两者)。对于git fetch
和git push
,这种refspec的含义是不同的。省略源代码需要包含一个冒号,而省略目标代码也可以使您也省略冒号。那就是:
master:master
或branch1:branch2
或tag:tag
等都提供源和目标。master
是没有目的地的来源。master:
也是没有目的地的来源。:master
是没有来源的目的地。这仅对git push
有效,这意味着要求另一个Git删除其引用。:
表示省略了源和目的地。这仅对git push
有效,这意味着找到匹配的分支名称并将其推送。忽略git push
,然后只允许源和目标,例如master:origin/master
或master:master
,或者不带源的目标,例如master
或{ {1}}。因此只有两种情况:
您提供了来源,但没有目的地。 master:
不会更新任何名称, 除外,因为自1.8.4起Git会机会性地更新默认获取引用规范中指定的所有远程跟踪名称。因此,如果您的Git至少为1.8.4,则git fetch
更新您的git fetch origin master
,这是您的origin/master
的Git的origin
的Git的远程跟踪名称。
您同时提供了源和目标。 master
将尝试更新目的地名称。如果未设置强制标志(全局标志或前导git fetch
),则此更新必须是快进的。如果您未指定+
,则目的地也不能是当前分支。 1 无论如何,如果您的Git为1.8.4或更高版本,您的Git会机会性地更新遥控器。 -跟踪名称作为源名称。
请注意:
--update-head-ok
(在命令行上不指定refspecs)将使用您配置中的默认refspecs。假设这是git fetch origin
,请参见origin
来查看那些默认的参考规范。
1 在我认为是个错误的情况下,此处针对 branch的测试已退出,仅测试 main 工作-tree的git config --get-all remote.origin.fetch
。如果当前已在添加的工作树中检出分支,则添加的工作树的索引和工作树将不再与其分支同步。另请参见Why does Git allow pushing to a checked-out branch in an added worktree? How shall I recover?-该错误在获取和推送之间是对称的。