“;git fetch——tags"包括“;git fetch"?

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

例如,如果我运行git fetch --tags,是否有理由在之后立即直接运行git fetch ?

那么git pullgit pull --tags呢?同样的情况?

248774 次浏览

我自己来回答这个问题。

我认为这是有区别的。"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 merge的包装器。建议你在跳转到git pull之前习惯手动git fetching和git mergeing,因为这可以帮助你首先理解git pull在做什么。

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

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

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

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

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

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

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

如果你想让它成为这个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之前用非快进的+覆盖本地分支和标签
  • 如果需要,覆盖当前签出的分支-u
  • 删除远程-p中不存在的分支和标记
  • 并强制确保-f

注意:从git 1.9/2.0(2014年第一季度)开始,git fetch --tags获取标记除了,这些标记是由相同的命令行获取的,没有选项。

只获取标签:

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

详细:

参见提交c5a84e9 by 迈克尔·哈格蒂(mhagger):

以前,fetch's "--tags"选项被认为等同于指定refspec

refs/tags/*:refs/tags/*

在命令行; 特别是,它导致remote.<name>.refspec配置被忽略 但是,在不获取其他引用的情况下获取标签是不太有用的,而能够获取标签除了其他引用是非常有用的。
因此,将该选项的语义改为后者

如果用户想获取只有标记,则仍然可以指定显式refspec:

git fetch <remote> 'refs/tags/*:refs/tags/*'
请注意,1.8.0.3之前的文档对“fetch --tags"的行为。
提交f0cb2f1 (2012-12-14) fetch --tags使文档匹配旧的行为。
这个提交修改文档以匹配新的行为(参见Documentation/fetch-options.txt)

请求从远程除了要获取的其他东西获取所有标签。


因为Git 2.5 (Q2 2015) git pull --tags更加健壮:

参见提交19 d122b by Paul Tan (pyokagan), 2015年5月13日。
(由Junio C Hamano—gitster提交cc77b99中合并,22 May 2015)

pull:在没有合并候选的情况下删除--tags错误

由于441年ed41 ("git pull --tags":错误输出了一个更好的消息。, 2007-12-28, Git 1.5.4+), git pull --tags将打印不同的错误消息 git-fetch没有返回任何合并候选项:

It doesn't make sense to pull all tags; you probably meant:
git fetch --tags
这是因为在那时,git-fetch --tags将覆盖任何 配置了refspecs,因此没有合并候选项。

.

.

.

然而,由于c5a84e9 (fetch --tags: fetch tags in addition to 其他东西,2013-10-30,Git 1.9.0+), git fetch --tags将获取额外的标签 到任何配置的refspecs。
因此,如果出现任何没有合并候选的情况,这并不是因为设置了--tags。因此,这个特殊的错误信息现在是不相关的

为防止混淆,请删除此错误消息。


在Git 2.11+(2016年Q4)中,git fetch更快。

参见提交5827年a03 (13 Oct 2016) by 杰夫·金(peff)
(由Junio C Hamano—gitster in 提交9 fcd144合并,2016年10月26日)

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

当从一个具有许多与我们所跟踪的分支无关的标记的远程获取时,我们曾经在检查标记所指向的对象(我们不打算获取!)是否存在于我们的存储库中时浪费了太多的周期。

这个补丁教fetch使用HAS_SHA1_QUICK来牺牲 准确的速度,在这种情况下,我们可能会用一个 同时重新打包。< / p >

下面是包含的perf脚本的结果,它设置了类似于上面描述的情况:

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. 在服务器端需要大量的标记引用,这些标记引用是自动跟踪的候选者(也就是说,客户端没有)。 每一个都触发对包目录的重新读取 在正常情况下,客户端会自动跟踪这些标记,在一次大的读取之后,(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年Q4)增加了另一项优化。

参见提交b7e2d8b (15 Sep 2019) by 铃木雅哉(draftcode)
(由Junio C Hamano—gitster提交1 d8b0df中合并,07 Oct 2019)

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

git fetch期间,客户端检查所发布的标签的OID是否已经在获取请求的想要的OID集中。
这种检查是在线性扫描中完成的。
对于一个有很多引用的存储库,重复这个扫描需要15分钟以上

为了加快这个过程,为其他引用的oid创建oid_set

git fetch upstream --tags

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