一个很好的简单的问题——“git fetch”函数是git fetch -tags的严格子集吗?

例如,如果我运行git fetch—tags,是否有理由立即运行git fetch ?

那"少不要脸"和"少不要脸"呢?同样的情况?


我自己来回答这个问题。

我认为这是有区别的。"git fetch——tags"可能会带来所有的标签,但它不会带来任何新的提交!

事实证明,必须这样做才能完全“更新”,即复制一个“git pull”而不合并:

$ git fetch --tags
$ git fetch

这很遗憾,因为它要慢一倍。如果“git fetch”有一个选项来做它通常做的事情,并带来所有的标签。

在大多数情况下,git fetch应该做你想做的事情,即“从远程存储库中获取任何新的东西,并将其放在本地副本中,而不合并到本地分支中”。Git fetch——tags就是这么做的,除了新标签,它什么都不获取。

从这个意义上说,git fetch——tags绝不是git fetch的超集。事实恰恰相反。

Git pull,当然,只是一个包装Git fetch <thisrefspec>;git合并。建议您在跳转到git pull之前先习惯手动git抓取和git合并,因为这可以帮助您首先理解git pull在做什么。

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

注意:这个答案只对git v1.8及更老版本有效。

大多数问题已经在其他的回答和评论中提到了,但这里有一个简明的解释:

Git获取所有分支头(或远程指定的所有分支头)。获取配置选项),所有必要的提交,以及所有可从这些分支访问的标记。在大多数情况下,所有标签都可以通过这种方式访问。 Git fetch——tags获取所有标签,所有必要的提交。它不会更新分支头,即使它们可以从所获取的标记中访问。

总结:如果你真的想要完全更新,只使用fetch,你必须两者都做。

它也不是“两倍慢”,除非你指的是在命令行上输入,在这种情况下,别名可以解决你的问题。发出这两个请求基本上没有开销,因为它们请求的是不同的信息。

这里的一般问题是git fetch将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/*"

如果你想让它成为这个repo的默认值,你可以添加第二个refspec到默认的取回:

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

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


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

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

就我而言,我想要这些功能

从遥控器抓取所有头部和标签,因此使用refspec refs/*:refs/* 在refspec之前使用非快进+覆盖本地分支和标记 如果需要,覆盖当前签出的分支 删除remote -p中不存在的分支和标签 当然还有力-f

注意:从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变得更加健壮:

参见Paul Tan (pyokagan) 2015年5月13日发表的commit 19d122b。 (由Junio C Hamano—gitster—在commit cc77b99中合并,2015年5月22日)

Pull: remove——标签错误,在没有合并候选的情况下

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年Q4)中,Git获取更快。

参见Jeff King (peff)提交5827a03(2016年10月13日)。 (由Junio C Hamano—gitster—在commit 9fcd144中合并,2016年10月26日)

获取:使用“quick”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%

这只适用于以下情况:

You have a lot of packs on the client side to make reprepare_packed_git() expensive (the most expensive part is finding duplicates in an unsorted list, which is currently quadratic). You need a large number of tag refs on the server side that are candidates for auto-following (i.e., that the client doesn't have). Each one triggers a re-read of the pack directory. Under normal circumstances, the client would auto-follow those tags and after one large fetch, (2) would no longer be true. But if those tags point to history which is disconnected from what the client otherwise fetches, then it will never auto-follow, and those candidates will impact it on every fetch.


Git 2.21(2019年2月)似乎引入了一个回归,当配置remote.origin.fetch不是默认配置时('+refs/heads/*:refs/remotes/origin/*')

fatal: multiple updates for ref 'refs/tags/v1.0.0' not allowed

Git 2.24(2019年Q4)增加了另一项优化。

参见Masaya Suzuki撰写的commit b7e2d8b(2019年9月15日)(草案代码)。 (由Junio C Hamano—gitster—在commit 1d8b0df中合并,2019年10月7日)

fetch:使用oidset保存想要的oid,以便更快地查找

在git获取过程中,客户端检查所发布的标签的OID是否已经在获取请求的想要的OID集中。 这种检查是在线性扫描中完成的。 对于一个有很多引用的存储库,重复这个扫描需要15分钟以上。 为了加快这个速度,为其他引用的oid创建一个oid_set。

git fetch upstream --tags

工作得很好,它只会得到新的标记,而不会得到任何其他代码基。