为什么git fetch没有获取任何标签?

11

我创建了一个沙盒 git 仓库,其中包含几个提交和几个标签,其中一个是轻量级的,另一个是注释型的:

> mkdir one; cd one; git init

> touch a.txt; git add a.txt; git commit -m"a.txt"

> touch b.txt; git add b.txt; git commit -m"b.txt"
> git tag light

> touch c.txt; git add c.txt; git commit -m"c.txt"
> git tag -a annot -m"annot"

现在我创建了第二个代码仓库并从第一个仓库中获取代码:

> mkdir two; cd two; git init

> git remote add one <...>/one
> git fetch one master
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 9 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
From <...>/one
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> one/master

为什么这两个标签都没有被获取?根据 Git fetch文档,我原本以为它们会被获取:
“默认情况下,任何指向正在获取的历史记录的标签也会被获取;其作用是获取指向您感兴趣的分支的标签。”

你尝试过 git fetch --all 吗? - Chandan Rai
我几乎可以确定Git的标签处理在这些年里发生了重大变化,所以:你正在运行哪个Git 版本?(如果这是在两台不同的机器上进行的,你使用的URL方案是http://还是git://还是ssh://,并且给出两台机器的Git版本...) - torek
@crai - git fetch --tags one master 和普通的 git fetch one 命令都会获取 one/master 分支以及 lightannot 标签。然而,git fetch one master 命令不会获取标签 - 我正在尝试理解其中的原因。 - user200783
@torek - 我正在使用最新的git版本,2.11.0。两个存储库都在同一台机器上,使用“file://”URL方案。 - user200783
2个回答

16

这不是一个确切的答案,但我通过谷歌搜索找到了这里,因为git fetch没有拉取我的标签(通常会拉取)。 所以这是给那些遇到同样问题的人的建议。

我能够手动使用以下命令拉取标签:git fetch --tags


2
这个答案很有用。我本来以为 git fetch --all 也会获取标签,但实际上它并没有。但是这个命令可以。谢谢! - rotarydial
这应该是被接受的答案。 - JBernardo
我也有同样的问题。很奇怪的是,git fetch神秘地并不总是像通常那样获取所有标签。 - friederbluemle
这是 Git 中的一个 bug 吗? - Matteo
git fetch 拉取了除一个标签外的所有标签。git fetch --tags 拉取了所有标签。现在即使我删除了所有标签,git fetch 仍然能正确地拉取它们。有趣的是。 - user1768761

8

编辑于2020年1月,根据Tim Bunce的评论:该行为被认为是一个错误,并在Git 2.20中进行了更改以使其更加合理。以下测试针对旧版本的Git。


更新了一些有趣的信息。我将其放入一个shell脚本中,以便进行简单测试:

mkdir ttwo && cd ttwo && git init && git remote add one file://[path]

(and then I remove ttwo after running a test).
因此,每次下面的测试都是在新的空白ttwo中运行。我这里使用的是Git 2.10.1,但与2.11相比应该没有显着差异(而与某些Linux发行版仍然附带的Git 1.7相比,肯定存在显着差异...)。
首先,让我们执行 refspecs的git fetch
$ git fetch one
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 8 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
From file://[path]
 * [new branch]      master     -> one/master
 * [new tag]         annot      -> annot
 * [new tag]         light      -> light

这是使用Git版本2.10.1,在同一台机器上使用file:///home/.../home/...,两个存储库都能获取到标签(如有需要可以在之间加入rm -rf texp2)。
现在让我们使用单个refspec master来运行它。从这里开始,我将省略remote:From:的部分,只显示更新的分支和/或标签。
$ git fetch one master
[snip]
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> one/master

如果我们使用 master:master,需要添加 --update-head-ok,将会发生以下情况:

$ git fetch one --update-head-ok master:master
 * [new branch]      master     -> master
 * [new tag]         annot      -> annot
 * [new branch]      master     -> one/master
 * [new tag]         light      -> light

啊哈,现在我们得到了标签!

如果我们获取master但将其写入refs/remotes/origin/master,会发生以下情况:

$ git fetch one master:refs/remotes/origin/master
 * [new branch]      master     -> origin/master
 * [new tag]         annot      -> annot
 * [new branch]      master     -> one/master
 * [new tag]         light      -> light

有一个模式正在出现:我们必须写入一些本地引用

让我们将 master 拉取到 x,并将 light 拉取到 dark(我尝试过将 foo 拉取到 bar,但这不起作用,因为 foo 在存储库中不存在):

$ git fetch one master:x light:dark
 * [new branch]      master     -> x
 * [new tag]         light      -> dark
 * [new tag]         annot      -> annot
 * [new tag]         light      -> light
 * [new branch]      master     -> one/master

现在让我们将master拉取到nothing,这会独立失败,但是将light拉取到dark:
$ git fetch one master light:dark
 * branch            master     -> FETCH_HEAD
 * [new tag]         light      -> dark
 * [new tag]         annot      -> annot
 * [new tag]         light      -> light
 * [new branch]      master     -> one/master

还有最后一个测试:

$ git fetch one master light
 * branch            master     -> FETCH_HEAD
 * tag               light      -> FETCH_HEAD
 * [new branch]      master     -> one/master

这并没有写入我们的标签,仅写入了FETCH_HEAD,同时进行了常规的机会主义远程跟踪分支更新。

总的来说,当给出显式的引用规范(refspecs)时,我们必须至少写入一个本地引用。不带引用规范的提取(fetching)可以正常工作,因为它使用配置文件中的默认引用规范以及默认标签。使用一些写入本地引用的引用规范进行提取(fetching)是可以工作的。只写入FETCH_HEAD 的引用规范进行提取则会失败。这似乎是一个错误,但Git代码的意图并不清楚,而且Git的标签更新代码非常复杂。


1
非常感谢您进行所有这些测试!根据证据,似乎确实需要至少一个显式目的地的显式refspec才能获取标签。因此,似乎获取'master'和相关标签的方法是git fetch one master:refs/remotes/one/master。您是否建议在git fetch one master的位置使用此命令? - user200783
1
@user200783:是的,假设配置是标准的(非镜像样式,在配置中没有其他有趣的fetch refspec)。如果您想在脚本中特别谨慎,可以运行git config --get-all remote.one.fetch并解析结果输出。我可能只会使用git fetch one master:refs/remotes/one/master。 :-) - torek
1
似乎这是一个行为错误或文档错误。没有提到默认标签被仅远程引用所覆盖的情况。 - torek
非常感谢@torek;我永远不会想到为什么相关标签没有被获取。手册上关于这个问题的说法是胡说八道。 - ankostis
2
FYI,自Git 2.20起,根据https://git-scm.com/docs/git-fetch的说明,“从Git版本2.20开始,更新refs/tags/*的获取方式与推送时相同。也就是说,如果在refspec(或--force)中没有+,则任何更新都将被拒绝。” - Tim Bunce
显示剩余5条评论

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