这些`git fetch`语法有什么区别?

10
我已经裸克隆了一个仓库(git clone --bare),显然git fetch不会更新它,但是git fetch origin master:master可以。我不理解这些语法之间的所有细微差别:
- git fetch - git fetch origin - git fetch origin master - git fetch origin master:master origin是我的唯一远程分支,master是我的唯一分支,帮助文档说:
当没有指定远程分支时,默认会使用 origin 远程分支
那么为什么这四行代码不相同呢?
编辑:前三个命令似乎在一个名为FETCH_HEAD的临时分支中获取。但由于我使用的是裸克隆,所以无法使用git merge来获取获取到的结果。
编辑2:根据@torek的答案,我进行了小测试并比较了裸克隆和镜像克隆目录。以下是结果:
diff -ru mesa.bare.git/config mesa.mirror.git/config
--- mesa.bare.git/config    2014-10-14 20:01:42.812226509 -0400
+++ mesa.mirror.git/config  2014-10-14 20:00:53.994985222 -0400
@@ -4,3 +4,5 @@
    bare = true
 [remote "origin"]
    url = git://anongit.freedesktop.org/mesa/mesa
+   fetch = +refs/*:refs/*
+   mirror = true
Only in mesa.bare.git/objects/pack: pack-17005b7e1020d291eb86d778a174ecf0d60d92a9.idx
Only in mesa.bare.git/objects/pack: pack-17005b7e1020d291eb86d778a174ecf0d60d92a9.pack
Only in mesa.mirror.git/objects/pack: pack-c08b44b7f290ef0bc9abe3a0b974695c85a69342.idx
Only in mesa.mirror.git/objects/pack: pack-c08b44b7f290ef0bc9abe3a0b974695c85a69342.pack

谢谢!


3
你读过 https://www.kernel.org/pub/software/scm/git/docs/git-fetch.html 吗?如果是的话,请编辑问题以澄清阅读后不清楚的内容(如果有)。否则,请自己回答问题(并在此处发布答案)! - Jesse W at Z - Given up on SE
2
当然我已经读过了,否则我怎么能引用 git help fetch 中的一句话呢? - Creak
2
通常情况下,你会想在配置的 origin 部分添加一行 "fetch = refs/heads/:ref/heads/",这样 git fetch 命令就能按预期工作了。 - Andrew C
啊,我应该注意到你引用了帮助文件。对于造成的困扰,我很抱歉。 - Jesse W at Z - Given up on SE
1个回答

15

Andrew C 的评论 在这里起了关键作用,但我会进一步阐述:

  • git fetch,没有其他参数,通过查看当前分支选择一个远程名称,或者使用 origin(有关详细信息,请参见文档)。然后选择一个远程,然后按照下一种形式进行操作。

  • git fetch remote,同样没有其他参数,使用给定的远程,提取该远程的 fetch = 行以获取一组“refspecs”。然后类似于上一种情况进行操作。

  • git fetch remote refspec 使用给定的远程和给定的 refspec(可以在此处给出多个 refspec)来选择要更新的引用。

一旦 git fetch 有了一个远程或 URL——给定一个远程名称,它会提取 url = 行以获取 URL——它会联系远程服务器上的其他 git 命令,并请求它们列出所有远程存储库的引用(分支、标签和其他引用,都在 refs/* 名称空间中,并加上特殊的 HEAD 添加,也可获取但通常在此处不使用——它是用于初始克隆步骤的)。

对于获得的每个引用,git fetch会查看您是否要求将该引用带过来,如果是,则会查看您要求 git 在 您的 存储库中使用的名称。

同样,可用的名称是从远程获得的。所需的名称是从您的 refspecs 获得的,并且它们在您的存储库中将使用的名称也是从您的 refspecs 获得的。

形如a:b的Refspec表示“使用引用a,但在本地称其为b”。

没有b部分的Refspec表示“使用引用a,但将其放入特殊文件FETCH_HEAD中。” (FETCH_HEAD然后就像普通引用一样,比如MERGE_HEADORIG_HEAD等等,只是它有一些额外的文本写入其中,供pull脚本使用,因此有时并不像您期望的那样工作。)

Refspec可能包含通配符:refs/heads/*表示“获取所有分支”(分支是以refs/heads/开头的引用的定义)。 通常,在您的Git配置中,fetch =行指定为refs/heads/*:refs/remotes/origin/*.1与之前一样,这意味着重命名匹配的分支,其中右侧的*扩展到左侧的*所匹配的内容。 这样可以将所有分支带来,但将它们重命名为origin/master等。 这通常适用于非--bare存储库。

有时候这也是你想要的--bare存储库,有时候不是。特别是,有时候你想要一个“镜像”存储库,它是一个简单地从另一个存储库复制的裸克隆。要将普通的裸仓库更改为这样的镜像,只需修改fetch =行:将refs/heads/*:refs/remotes/origin/*修改为fetch = refs/heads/*:refs/heads/*。实际上,您可能希望使用fetch = refs/*:refs/*来搬运一切(包括标签和注释)。当然,是否真的需要这样做,只有您自己才能决定。
请注意,这种情况非常常见,以至于git clone有一个标志可以自动设置它:使用--mirror进行克隆,你会得到一个带有修改后的fetch =行的裸克隆。
1实际上这一行读作+refs/heads/*:refs/remotes/origin/*,即还有一个前导+字符。此加号设置了“强制标志”,就好像你使用了git fetch --force一样,针对该特定参考更新。这与此处的拼写问题没有特别关系,但我要注意的是,通常你希望远程分支像此处列出的那样进行强制更新,以及纯镜像存储库。
如果你在镜像标签,你可能希望它们执行强制更新。当然,在理想世界中,标签永远不会被更改(也不会被删除),因此这并不重要,但在现实世界中它们有时会更改或被删除。
要处理引用删除,必须告诉git fetch--prune(或者同样地,提供--prunegit remote update)。在refspec中没有自动修剪的语法(虽然这是合理的,但我没有看到任何建议)。

感谢您提供这个完整的答案!请查看“Edit2”。 - Creak
显然,在我的情况下添加 fetch = refs/heads/*:refs/heads/* 并不像我期望的那样起作用。因为在克隆时我还使用了 --depth 6000,将这行代码添加到我的 config 文件中会使 git fetch 尝试获取整个存储库。但是如果输入 fetch = master:master,那么一切都正常工作! - Creak
我从未尝试过浅克隆,但是假设当你复制refs/heads/*时,你会得到一个导致git加深仓库的分支;但是使用master:master,你只复制了master(git会自动将其限定为refspec的两侧的refs/heads/master),并且它会在遇到你已经有的提交时停止,因此只有在合并不在你的600中的提交时,它才会加深克隆。 - torek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接