这些 `git fetch` 语法有啥区别?

Posted

技术标签:

【中文标题】这些 `git fetch` 语法有啥区别?【英文标题】:What is the difference between these `git fetch` syntaxes?这些 `git fetch` 语法有什么区别? 【发布时间】:2014-12-08 15:51:15 【问题描述】:

我已经裸克隆了一个存储库 (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 是我唯一的分支,帮助说:

当没有指定遥控器时,默认使用原始遥控器

那么为什么这四行不一样呢?

编辑:前三个命令似乎在一个名为 FEATCH_HEAD 的临时分支中获取。但由于我使用的是裸克隆,因此无法使用git merge 获取获取的结果。

Edit2: 根据@torek 的回答,我做了一个小测试并区分了 --bare 和 --mirror 克隆目录。结果如下:

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

谢谢!

【问题讨论】:

你读过kernel.org/pub/software/scm/git/docs/git-fetch.html 吗?如果是这样,请编辑问题以澄清阅读后不清楚的地方(如果有的话)。否则,请自己回答问题(并在此处发布答案)! 当然看过了,不然怎么引用git help fetch的一句话? 通常你会希望在你的配置的原始部分有一个像“fetch = refs/heads/*:ref/heads/*”这样的行,然后它会让git fetch表现得像你期待 啊,我应该注意到你引用了帮助。抱歉打扰了。 【参考方案1】:

Andrew C's comment 包含这里的密钥,但我会稍微解释一下:

git fetch,没有附加参数,通过查看当前分支选择远程名称,或使用origin(有关详细信息,请参阅文档)。选择了遥控器后,它会继续下一个表单。

git fetch <em>remote</em>,同样没有附加参数,使用给定的遥控器,并提取该遥控器的fetch = 行以获得一组“refspecs”。然后它与上一种情况类似。

git fetch <em>remote</em> <em>refspec</em> 使用给定的远程和给定的 refspec(您可以在此处提供多个 refspec)来选择要更新的引用。

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

对于如此获得的每个引用,git fetch 会查看您是否要求它提供该引用,如果是,您要求 git 在您的存储库中使用什么名称。

同样,available 的名称是从远程获取的。 wanted 的名称是从您的 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(或者,类似地,将--prune 提供给git remote update)。 refspecs 中没有用于自动修剪的语法(虽然这很合理,但我还没有看到任何建议)。

【讨论】:

感谢您的完整回答!请参阅“Edit2”。 显然添加 fetch = refs/heads/*:refs/heads/* 在我的情况下无法正常工作。因为我在克隆过程中也使用了--depth 6000,所以将此行添加到我的config 文件会使git fetch 尝试获取整个存储库。但是如果输入fetch = master:master,那么一切正常! 我从未尝试过浅克隆,但大概当你带来refs/heads/* 时,你会得到一个导致 git 加深 repo 的分支;但是使用master:master,你只带来master(git自动将其限定为refs/heads/master,在refspec的两侧)并且当它遇到你拥有的提交时它会停止,所以它只会加深克隆如果你合并一个尚未在您的 600 中的提交。

以上是关于这些 `git fetch` 语法有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

git branch、fork、fetch、merge、rebase 和 clone 有啥区别?

Git 提交范围中的双点“..”和三点“...”有啥区别?

这些语法有啥区别,请详细解释一下?

isomorphic-fetch 和 fetch 有啥区别?

Fetch 和 Query 有啥区别?

fetch 和 jquery ajax 有啥区别?