这些 `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_HEAD
和ORIG_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 有啥区别?