为什么 git fetch 不获取任何标签? [英] Why is git fetch not fetching any tags?

查看:38
本文介绍了为什么 git fetch 不获取任何标签?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个沙箱 git 存储库,其中包含一些提交和几个标签,一个是轻量级的,一个是带注释的:

I have created a sandbox git repository containing a few commits and a couple of tags, one lightweight and one annotated:

> 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"

我现在创建第二个存储库并从第一个获取:

I now create a second repository and fetch from the first:

> 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:

Why have neither of the tags been fetched? I expected they would be, based on 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 月,根据 Tim Bunce 的评论:该行为被认为是一个错误,并在 Git 2.20 中进行了更改以更明智.以下测试适用于较旧版本的 Git.

Edit, Jan 2020, per Tim Bunce's comment: the behavior was deemed to be a bug and changed in Git 2.20 to be more sensible. The tests below are for significantly older versions of Git.

更新了新的有趣的信息位.为了方便测试,我把它放到了一个 shell 脚本中:

Updated with new interesting informational bits. I put this into a shell script for easy testing:

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

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

(and then I remove ttwo after running a test).

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

Hence each test below is run in the new empty ttwo. I am also using Git 2.10.1 here, but there should be no significant differences with 2.11 (while there are definitely significant differences compared with Git 1.7, which is still shipping with certain Linux distributions...).

首先,让我们使用 no refspecs git fetch:

First, let's git fetch with no 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)都拾取了两个标签.

This is with Git version 2.10.1, with both repositories on the same machine, and using either file:///home/... or /home/.... Both fetches (rm -rf texp2 in between as needed) picked up both tags.

现在让我们使用单个 refspec master 运行它.从这里开始,我将省略 remote:From: 的内容,只显示更新了哪些分支和/或标签:

Now let's run it with the single refspec master. From here on I'll leave out the remote: through From: stuff, just show what branches and/or tags get updated:

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

如果我们使用 master:master 会发生什么,这需要添加 --update-head-ok:

Here's what happens if we use master:master, which requires adding --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

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

Aha, now we get tags!

如果我们获取 master 并将其写入 refs/remotes/origin/master 会发生什么:

Here's what happens if we fetch master but write it to 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(s)

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

There is a pattern emerging: we have to write to some local ref(s)

Let's fetch master to x and light to dark (I tried foo to bar but that doesn't work because foo does not exist in 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:

Now let's fetch master to nothing, which we know fails standalone, but fetch light to 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,加上通常的机会主义远程跟踪分支更新.

This did not write to our tags, only to FETCH_HEAD, plus the usual opportunistic remote-tracking branch update.

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

The bottom line appears to be that, when giving explicit refspecs, we must write at least one local ref. Fetching with no refspecs works, because that uses the default refspecs in the config file plus the default tags. Fetching with some refspec(s) that write to a local ref works. Fetching with some refspec(s) that only write to FETCH_HEAD fails. This seems like a bug, but it's not clear what the intent of the code in Git is, and Git's tag update code is horribly twisty.

这篇关于为什么 git fetch 不获取任何标签?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆