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

Why is git fetch not fetching any tags?

我创建了一个沙箱 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

为什么两个标签都没有被提取?我预计他们会,基于 the documentation for git fetch:

By default, any tag that points into the histories being fetched is also fetched; the effect is to fetch tags that point at branches that you are interested in.

编辑,2020 年 1 月,根据 :该行为被认为是一个错误,并在 Git 2.20 中更改为更合理。下面的测试是针对 Git.

的明显较旧的版本

更新了有趣的新信息位。我将其放入 shell 脚本中以便于测试:

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

(然后我在 运行 测试后删除了 ttwo)。

因此下面的每个测试都是 运行 在新的空 ttwo 中。我在这里也使用 Git 2.10.1,但与 2.11 应该没有显着差异(虽然与 Git 1.7 相比肯定有显着差异,后者仍在某些 Linux分布...)。

首先,让我们git fetch 没有 refspecs:

$ 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: 的内容,只显示更新了哪些分支 and/or 标签:

$ 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

出现了一种模式:我们必须写入一些本地 ref

让我们获取 masterxlightdark(我试过 foobar 但那不起作用因为 foo 在 repo one 中不存在):

$ 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,加上通常的机会主义 remote-tracking 分支更新。

底线似乎是,在给出显式引用规范时,我们必须写 至少一个 本地引用。使用 no refspecs 获取是有效的,因为它使用配置文件中的默认 refspecs 加上默认标签。使用一些写入本地 ref 的 refspec 进行获取。使用某些仅写入 FETCH_HEAD 的 refspec 获取失败。这似乎是一个错误,但不清楚 Git 中代码的意图是什么,而且 Git 的标签更新代码非常曲折。

不是真正的答案,但我是通过 Google 搜索找到这里的,因为 git fetch 没有提取我的标签(而且通常会这样做)。因此,这适用于偶然发现这个措辞非常相似的问题的同一条船上的其他人。

我能够通过以下方式手动拉取标签:git fetch --tags