“git fetch --tags”命令包括“git fetch”吗?

304

一个简单而不失优雅的问题 - "git fetch"的功能是否严格是git fetch --tags的子集?

也就是说,如果我运行git fetch --tags,有必要立即运行git fetch吗?

git pullgit pull --tags呢?情况一样吗?


11
从 Git 1.9/2.0(2014年第一季度)开始,答案将是“是”。请参见我下面的回答 - VonC
3
针对“修改我的文本”的编辑,一个连字符后面或首字母缩略词后面不一定需要大写,因此您的修改在语法上是错误的,这就是为什么我拒绝了它。 - davidA
6个回答

216
注意:从git 1.9/2.0(2014年第一季度)开始,git fetch --tags除了使用相同的命令行而不带选项获取的内容外,还会获取标签

要仅获取标签:

git fetch <remote> 'refs/tags/*:refs/tags/*'

具体来说:

查看Michael Haggerty(mhagger)提交的commit c5a84e9:

Previously, fetch's "--tags" option was considered equivalent to specifying the refspec

refs/tags/*:refs/tags/*

on the command line; in particular, it caused the remote.<name>.refspec configuration to be ignored.

But it is not very useful to fetch tags without also fetching other references, whereas it is quite useful to be able to fetch tags in addition to other references.
So change the semantics of this option to do the latter.

If a user wants to fetch only tags, then it is still possible to specifying an explicit refspec:

git fetch <remote> 'refs/tags/*:refs/tags/*'

Please note that the documentation prior to 1.8.0.3 was ambiguous about this aspect of "fetch --tags" behavior.
Commit f0cb2f1 (2012-12-14) fetch --tags made the documentation match the old behavior.
This commit changes the documentation to match the new behavior (see Documentation/fetch-options.txt).

请求从远程获取所有标签,除了正在获取的其他内容之外
自 Git 2.5 (2015 年第二季度) 起,git pull --tags 更加健壮:
请参阅 commit 19d122b,作者为 Paul Tan (pyokagan), 发布于 2015 年 5 月 13 日。
(由 Junio C Hamano -- gitster -- 合并于 commit cc77b99,发布于 2015 年 5 月 22 日)

pull: 移除在无合并候选情况下的 --tags 错误

Since 441ed41 ("git pull --tags": error out with a better message., 2007-12-28, Git 1.5.4+), git pull --tags would print a different error message if git-fetch did not return any merge candidates:

It doesn't make sense to pull all tags; you probably meant:
      git fetch --tags

This is because at that time, git-fetch --tags would override any configured refspecs, and thus there would be no merge candidates. The error message was thus introduced to prevent confusion.

However, since c5a84e9 (fetch --tags: fetch tags in addition to other stuff, 2013-10-30, Git 1.9.0+), git fetch --tags would fetch tags in addition to any configured refspecs.
Hence, if any no merge candidates situation occurs, it is not because --tags was set. As such, this special error message is now irrelevant.

To prevent confusion, remove this error message.


从Git 2.11+(2016年第四季度)开始,git fetch更快了。

请参见提交 5827a03(由Jeff King(peff于2016年10月13日完成)。
(由Junio C Hamano -- gitster --提交9fcd144中合并,于2016年10月26日)

fetch:使用“快速”has_sha1_file来跟随标签

When fetching from a remote that has many tags that are irrelevant to branches we are following, we used to waste way too many cycles when checking if the object pointed at by a tag (that we are not going to fetch!) exists in our repository too carefully.

This patch teaches fetch to use HAS_SHA1_QUICK to sacrifice accuracy for speed, in cases where we might be racy with a simultaneous repack.

Here are results from the included perf script, which sets up a situation similar to the one described above:

Test            HEAD^               HEAD
----------------------------------------------------------
5550.4: fetch   11.21(10.42+0.78)   0.08(0.04+0.02) -99.3%
这仅适用于以下情况:
  1. 客户端有大量包使得reprepare_packed_git()变得昂贵(最昂贵的部分是在未排序列表中查找重复项,目前是二次方的)。
  2. 服务器端需要大量标签引用作为自动跟随的候选项(即客户端没有的标签引用)。每个标签引用都会触发重新读取包目录。
  3. 在正常情况下,客户端将自动跟随这些标签引用,在一次大型获取之后,(2)不再成立。
    但是,如果这些标签引用指向与客户端其他获取不相关的历史记录,则它永远不会自动跟随,并且这些候选项将影响每次获取。

Git 2.21(2019年2月)似乎引入了一个回归问题,当config remote.origin.fetch不是默认值'+refs/heads/*:refs/remotes/origin/*')时。
fatal: multiple updates for ref 'refs/tags/v1.0.0' not allowed

Git 2.24(2019年第四季度)增加了另一项优化。
请参见commit b7e2d8b(由Masaya Suzuki (draftcode)于2019年9月15日提交)。
(由Junio C Hamano -- gitster --commit 1d8b0df中合并,于2019年10月7日)

fetch:使用oidset来保存想要的OID以进行更快的查找

git fetch期间,客户端会检查广告标签的OID是否已经在获取请求的want OID集中。
这个检查是通过线性扫描来完成的。
对于具有大量引用的存储库,重复执行此扫描需要15分钟以上的时间。
为了加速此过程,请为其他引用的OID创建一个oid_set

这个git-list线程讨论了修改git fetch <remote> <branch>行为以自动跟随标签的可能性(因为它已经根据原意更新了远程跟踪):https://public-inbox.org/git/xmqqwp62f0dm.fsf@gitster.mtv.corp.google.com/ - ankostis
@ankostis 有趣的是,正如 Junio 在 https://public-inbox.org/git/xmqqk222expv.fsf@gitster.mtv.corp.google.com/ 中提到的那样,“回到旧的行为可能是解决本主题中讨论的问题的一个选项。” (但他们不会这样做:https://public-inbox.org/git/xmqq8tie8cfc.fsf@gitster.mtv.corp.google.com/) - VonC
Git是否有可能向最终用户公开更多不必要的复杂性,需要使用语法繁重的命令来执行常见操作,以至于看起来像是一些hack?我认为还没有足够的内部知识需要了解。 - John Fantastico
1
@JohnFantastico 我能理解那个观点。我之前也看到过这种情况:https://news.ycombinator.com/item?id=16587496 或者 https://hackernoon.com/https-medium-com-zspajich-understanding-git-data-model-95eb16cc99f5(“Git 命令只是对数据存储的泄漏抽象。”) - VonC
1
@Vadorequest 谢谢。我已经更新了答案,并会关注邮件列表:https://public-inbox.org/git/?q=fetch - VonC
显示剩余3条评论

133

注意:本回答仅适用于git v1.8及更早版本。

大部分内容已经在其他回答和评论中提到,这里给出一个简洁的解释:

  • git fetch 拉取所有分支头(或由远程.fetch配置选项指定的所有分支头)、它们所需的所有提交以及可从这些分支访问的所有标签。在大多数情况下,所有标签都可以通过这种方式访问。
  • git fetch --tags 拉取所有标签及其所需的所有提交。即使它们可从获取的标签访问,它也不会更新分支头。

总结:如果你真的想要完全保持最新状态,只使用fetch,那么你必须同时使用这两个命令。

除非你指的是在命令行上输入命令的时间,否则这并不会导致速度“减慢一倍”。由于它们在请求不同的信息,因此基本没有开销。


2
感谢您的评论。我在高延迟网络上使用Cygwin运行git - 当没有要获取的内容时,速度会慢两倍(大约5秒)。 - davidA
7
请注意,git remote update并不能完全替代git fetchgit fetch --tags。虽然git remote update会拉取新的标签,但不会更新已经改变的现有标签。只有git fetch --tags才能更新已经存在的标签。 - larsks
@gnarf 此外,标签在实践中仅应存在于分支上,因此获取标签只是获取引用,没有打包开销。 - Cascabel
@Jefromi我们不会覆盖标签,而是使其成为孤立状态。在每个发布中添加了一些文件,我们不希望在任何分支中出现。标准fetch无法检索它们。 - gnarf
“以及从这些分支可达的所有标签” 你能详细说明一下这是什么意思吗?有什么方法可以使标签可达?有什么方法可以使其不可达? - Daniel Kaplan
显示剩余9条评论

54

我将自己回答这个问题。

我已经确定有区别。 "git fetch --tags" 可能会带来所有的标签,但它不会带来任何新的提交!

事实证明,要完全"更新到最新",即复制一个 "git pull" 而不是合并,必须执行以下操作:

$ git fetch --tags
$ git fetch

这很遗憾,因为它要慢两倍。如果 "git fetch" 有一个选项,可以像通常一样执行,并同时带入所有标签,那就好了。


1
一个 'git remote update myRemoteRepo' 怎么样:它会获取远程内容和标签吗? - VonC
git fetch --tags会获取所有支持远程存储库标签的提交,但它不会获取在远程存储库标签集中未包含的分支上的提交。 - CB Bailey
2
我经常执行 git fetch 命令,它总是拉取任何新的提交和标签。你正在使用哪个版本的 Git? - Tim Visher
4
FTR,“git remote update myRemoteRepo” 的效果不佳 - 似乎无法像“git fetch && git fetch --tags”那样工作,特别是后续的合并没有任何效果。 - davidA
1
git fetch 不会获取未在分支的提交日志中的标签。例如,jQuery UI 在发布标记上执行此操作。我们执行 git checkout -b temp-branch,进行发布、添加所需的文件、更新版本等操作,然后执行 git commit -m "1.10.x" ; git tag 1.10.x; git push --tags,最后删除本地的临时分支。没有远程分支与该标记相连,因此 git fetch 永远不会下载它。 - gnarf
显示剩余2条评论

32
这里的一般问题是git fetch将获取+refs/heads/*:refs/remotes/$remote/*。如果这些提交中有标签,那么这些标签也将被获取。但是,如果有标签对远程分支不可达,则不会被获取。 --tags选项将refspec切换为+refs/tags/*:refs/tags/*。你可以要求git fetch同时抓取两者。我相信只需执行git fetch && git fetch -t,你就可以使用以下命令:
git fetch origin "+refs/heads/*:refs/remotes/origin/*" "+refs/tags/*:refs/tags/*"

如果您想将此设置为该存储库的默认设置,则可以将第二个refspec添加到默认的fetch中:

git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"

这将在此远程的.git/config中添加第二个fetch =行。


我花了一段时间寻找处理项目的方法。这是我想出来的。

git fetch -fup origin "+refs/*:refs/*"

在我的情况下,我想要这些功能:
  • 获取来自远程的所有头文件和标签,因此使用refspec refs/*:refs/*
  • 在refspec之前使用非快进+覆盖本地分支和标签
  • 如有必要,覆盖当前检出的分支-u
  • 删除不存在于远程的分支和标签-p
  • 并强制执行以确保-f

1
这应该是答案。 - redolent
“--tags”选项将refspec切换为“+refs/tags/*:refs/tags/”,而“man git-fetch”似乎指定了没有前导“+”的refspec(“refs/tags/:refs/tags/*”)。 - Dmitry Minkovsky
remote.origin.fetch 默认为 +refs/heads/*:refs/remotes/origin/*,也就是说使用了 + 版本,对吧?(这意味着,无论 origin/branch 目前在本地的哪个位置,它都将被覆盖。) - Robert Siemer
...在撰写本文时,最近的 git --tags 正在获取标签,_除了_已经存在的所有内容。请参见 @VonC 的答案。 - Robert Siemer

11
在大多数情况下,git fetch 应该可以满足你的需求,它会“从远程仓库获取任何新的内容并将其放入本地副本中,但不会合并到本地分支”。git fetch --tags 正是这样做的,除了它只获取新标签,而不会获取其他的。

从这个意义上讲,git fetch --tags 绝不是 git fetch 的超集。实际上,它恰恰相反。

git pull 本质上只是 git fetch <thisrefspec>; git merge 的一个包装器。建议在转向 git pull 之前先习惯手动执行 git fetchgit merge,因为这有助于理解 git pull 的操作方式。

话虽如此,与 git fetch 的关系完全相同。 git pullgit pull --tags 的超集。


1
"git pull是git pull --tags的超集,但是'git fetch'并不是'git fetch --tags'的超集,因此两者之间的关系并不完全相同...?" - davidA
9
刚刚发现这个问题... 好吧,我觉得 git pull 不会获取 所有 标签,而只会获取当前分支头可达的标签。然而,git pull --tags 可以获取所有标签,看起来等同于 git fetch --tags - Arc

3
git fetch upstream --tags

这个功能完全正常,只会添加新标签而不会获取任何其他代码库。


2
“upstream” 通常被称为 “origin”。我认为 “upstream” 是 GitHub 使用的名称。无论如何,要使用的名称是由 “git remote” 显示的名称。 - Fabio says Reinstate Monica
fatal: 'upstream' does not appear to be a git repository - alper

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