什么是 git 标签,如何创建标签以及如何检出 git 远程标签

What is git tag, How to create tags & How to checkout git remote tag(s)

当我签出远程 git 标签时,使用如下命令:

git checkout -b local_branch_name origin/remote_tag_name

我遇到这样的错误:

error: pathspec origin/remote_tag_name did not match any file(s) known to git.

当我使用git标签命令时,我可以找到remote_tag_name。

让我们先解释一下 git 中的标签是什么

A tag is used to label and mark a specific commit in the history.
It is usually used to mark release points (eg. v1.0, etc.).

Although a tag may appear similar to a branch, a tag, however, does not change. It points directly to a specific commit in the history and will not change unless explicitly updated.


如果标签不在本地存储库中,您将无法签出标签,因此首先,您必须 fetch 将标签添加到本地存储库。

首先,通过

确保标签在本地存在
# --all will fetch all the remotes.
# --tags will fetch all tags as well
$ git fetch --all --tags --prune

然后通过运行

查看标签
$ git checkout tags/<tag_name> -b <branch_name>

使用 tags/ 前缀代替 origin


在此示例中,您有 2 个标签版本 1.0 和版本 1.1,您可以使用以下任一方法检查它们:

$ git checkout A  ...
$ git checkout version 1.0  ...
$ git checkout tags/version 1.0  ...

以上所有内容都将执行相同的操作,因为标记只是指向给定提交的指针。


来源:https://backlog.com/git-tutorial/img/post/stepup/capture_stepup4_1_1.png


如何查看所有标签的列表?

# list all tags
$ git tag

# list all tags with given pattern ex: v-
$ git tag --list 'v-*'

如何创建标签?

有两种创建标签的方法:

# lightweight tag 
$ git tag 

# annotated tag
$ git tag -a

两者之间的区别在于,在创建带注释的标签时,您可以像在 git 提交中一样添加元数据:
姓名、电子邮件、日期、评论和签名

如何删除标签?

删除本地标签

$ git tag -d <tag_name>
Deleted tag <tag_name> (was 000000)

注意:如果你尝试删除一个不存在的Git标签,将会看到如下错误:

$ git tag -d <tag_name>
error: tag '<tag_name>' not found.

删除远程标签

# Delete a tag from the server with push tags
$ git push --delete origin <tag name>

如何克隆特定标签?

为了抓取给定标签的内容,可以使用checkout命令。如上所述,标签就像任何其他提交一样,因此我们可以使用 checkout 而不是使用 SHA-1,只需将其替换为 tag_name

选项 1:

# Update the local git repo with the latest tags from all remotes
$ git fetch --all

# checkout the specific tag
$ git checkout tags/<tag> -b <branch>

选项2:

使用克隆命令

由于 git 通过将 --branch 添加到克隆命令来支持 浅克隆 我们可以使用标签名称而不是分支名称。 Git 知道如何将给定的 SHA-1“翻译”为相关提交

# Clone a specific tag name using git clone 
$ git clone <url> --branch=<tag_name>

git clone --branch=

--branch can also take tags and detaches the HEAD at that commit in the resulting repository.


如何推送标签?

git push --tags

推送所有标签:

# Push all tags
$ git push --tags 

使用 refs/tags 而不是仅指定 <tagname>

为什么?

  • 建议使用 refs/tags,因为有时标签可以与您的分支同名,简单的 git 推送将推送分支而不是标签

要推送带注释的标签和当前历史链标签,请使用:

git push --follow-tags

这个标志--follow-tags同时推送提交仅标签,它们都是:

  • 带注释的标签(因此您可以跳过 local/temp 构建标签)
  • 当前分支(位于历史记录中)的可达标签(祖先)

从Git 2.4开始你可以使用配置

$ git config --global push.followTags true

备忘单:


(这个回答花了点时间,在目的和本质上是正确的,但并不完全,所以我还是post这个。)


没有"remote Git tag"这样的东西。只有 "tags"。我指出所有这些并不是迂腐,1 而是因为休闲 Git 用户对此有很多困惑,并且 Git 文档是对初学者帮助不大2。 (目前尚不清楚混乱是因为文档不完善,还是文档不完善是因为这本身就有些混乱,或者是什么。)

"remote branches",更恰当的称呼是"remote-tracking branches",但值得注意的是,这些实际上是本地实体。但是,没有远程标签(除非您(重新)发明它们)。只有本地标签,需要在本地获取标签才能使用。

特定提交名称的一般形式——Git 调用 references——是任何以 refs/ 开头的字符串。以refs/heads/开头的字符串命名一个分支;以 refs/remotes/ 开头的字符串命名远程跟踪分支;以 refs/tags/ 开头的字符串命名一个标签。名称 refs/stash 是存储引用(由 git stash 使用;注意缺少尾部斜杠)。

有一些不以 refs/ 开头的不常见的特殊名称:特别是 HEADORIG_HEADMERGE_HEADCHERRY_PICK_HEAD也都是可能引用特定提交的名称(尽管 HEAD 通常包含分支的名称,即包含 ref: refs/heads/<em>branch</em>).但一般来说,引用以 refs/.

开头

Git 造成混淆的一件事是它允许您省略 refs/,并且通常是 refs/ 之后的词。例如,您可以在引用本地分支或标签时省略 refs/heads/refs/tags/——事实上,您 必须 在结帐时省略 refs/heads/当地分行!您可以在结果明确时执行此操作,或者——正如我们刚刚提到的——当您必须执行此操作时(对于 git checkout <em>branch</em>).

的确,引用不仅存在于您自己的存储库中,也存在于远程存储库中。但是,Git 只允许您在非常特定的时间访问远程存储库的引用:即在 fetchpush 操作期间。您也可以使用git ls-remotegit remote show来查看它们,但fetchpush是更有趣的联系点。

参考规格

fetchpush 期间,Git 使用它调用的字符串 refspecs 在本地和远程存储库之间传输引用。因此,正是在这些时候,通过 refspecs,两个 Git 存储库可以相互同步。一旦您的名字同步,您就可以使用与远程用户相同的名字。不过,fetch 上有一些特殊的魔法,它会影响分支名称和标签名称。

您应该将 git fetch 视为指示您的 Git 呼叫(或可能是短信)另一个 Git——"remote"——并进行对话用它。在此对话的早期,遥控器列出了它的所有引用:refs/heads/ 中的所有内容和 refs/tags/ 中的所有内容,以及它拥有的任何其他引用。您的 Git 扫描这些并(基于通常的获取 refspec)重命名 它们的分支。

让我们看一下名为 origin:

的遥控器的正常 refspec
$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
$ 

此 refspec 指示您的 Git 获取每个匹配 refs/heads/* 的名称——即远程上的每个分支——并将其名称更改为 refs/remotes/origin/*,即保留匹配的部分同样,将分支名称 (refs/heads/) 更改为远程跟踪分支名称 (refs/remotes/,具体来说,refs/remotes/origin/)。

通过此 refspecorigin 的分支成为远程 origin 的远程跟踪分支。分支名称成为远程跟踪分支名称,包含远程名称,在本例中为 origin。 refspec 前面的加号 + 设置 "force" 标志,即,您的远程跟踪分支将被更新以匹配远程的分支名称,无论需要什么才能使其匹配。 (如果没有 +,分支更新仅限于 "fast forward" 更改,并且自 Git 版本 1.8.2 以来标签更新被简单地忽略——在此之前应用相同的快进规则。 )

标签

但是标签呢?它们没有 refspec——至少,默认情况下没有。您可以设置一个,在这种情况下,refspec 的形式由您决定;或者你可以 运行 git fetch --tags。使用 --tags 具有将 refs/tags/*:refs/tags/* 添加到 refspec 的效果,即,它会带来所有标签( 但不会更新 你的 标签,如果您已经有一个具有该名称的标签,不管遥控器的标签是什么 编辑,2017 年 1 月:截至 Git 2.10,测试表明 --tags 强制从远程标签更新您的标签,就像 refspec 读取 +refs/tags/*:refs/tags/* 一样;这可能与早期版本的 Git).

在行为上有所不同

注意这里没有重命名:如果远程 origin 有标签 xyzzy,而你没有,而你 git fetch origin "refs/tags/*:refs/tags/*",你会添加 refs/tags/xyzzy到您的存储库(指向与远程相同的提交)。如果您使用 +refs/tags/*:refs/tags/*,那么您的标签 xyzzy,如果您有的话, 替换为来自 origin 的标签。也就是说,refspec 上的 + 强制标志表示 "replace my reference's value with the one my Git gets from their Git".

提取期间的自动标记

由于历史原因,3 如果您既不使用 --tags 选项也不使用 --no-tags 选项,git fetch 会采取特殊操作。请记住,我们在上面说过,远程首先向您的本地 Git 所有 显示其引用,无论您的本地 Git 是否想要查看它们。4 您的 Git 记下此时看到的所有标签。 然后,当它开始下载它需要处理的任何提交对象时,如果其中一个提交与任何这些标签具有相同的 ID,git 将添加该标签——或那些标签,如果多个标签具有该 ID — 到您的存储库。

编辑,2017 年 1 月:测试表明 Git 2.10 中的行为现在是:如果他们的 Git 提供名为 T 的标签,and 您没有名为 T 的标签,andT 关联的提交 ID 是您的 git fetch 正在检查的其中一个分支的祖先,您的 Git 将 T 添加到您的标签中,有或没有 --tags.添加 --tags 会导致您的 Git 获得 所有 他们的标签,并强制更新。

底线

您可能需要使用 git fetch --tags 来获取他们的标签。如果他们的标签名称与您现有的标签名称冲突,您 可能 (取决于 Git 版本)甚至必须删除(或重命名)您的一些标签,然后 运行 git fetch --tags,获取他们的标签。由于标签(与远程分支不同)没有自动重命名,您的标签名称必须与其标签名称匹配,这就是您可能遇到冲突问题的原因。

大多数 正常情况下,虽然,一个简单的 git fetch 就可以完成工作,带来他们的提交和他们匹配的标签,并且因为他们 - 无论他们是谁- 将在他们发布这些提交时标记提交,您将跟上他们的标签。如果您不制作自己的标签,也不混合他们的存储库和其他存储库(通过多个远程),您也不会有任何标签名称冲突,因此您不必为了删除或重命名标签而大惊小怪获取他们的标签。

当您需要限定名称时

我在上面提到过,您几乎总是可以省略 refs/,并且大多数时候可以省略 refs/heads/refs/tags/ 等等。但是当不能你呢?

完整(或接近完整)的答案在 the gitrevisions documentation 中。 Git 将使用 link 中给出的六步序列将名称解析为提交 ID。奇怪的是,标签会覆盖分支:如果有一个标签 xyzzy 和一个分支 xyzzy,并且它们指向不同的提交,那么:

git rev-parse xyzzy

将为您提供标签指向的 ID。然而——这正是 gitrevisions 所缺少的——git checkout 更喜欢分支名称,因此 git checkout xyzzy 会把你放在分支上,而忽略标签。

如果出现歧义,您几乎总是可以使用其全名 refs/heads/xyzzyrefs/tags/xyzzy 拼出参考名称。 (请注意,此 确实 git checkout 一起工作,但可能以一种意想不到的方式:git checkout refs/heads/xyzzy 导致分离 HEAD 检出而不是分支检出。这就是为什么你只需要注意 git checkout 将首先使用短名称作为分支名称:即使标签 xyzzy 存在,这就是你签出分支 xyzzy 的方式。如果你想检查出标签,你可以使用refs/tags/xyzzy.)

因为(如 gitrevisions 注释)Git 将尝试 refs/<em>name</em>,您也可以简单地写入 tags/xyzzy 以识别标记为 xyzzy 的提交。 (如果有人设法将名为 xyzzy 的有效引用写入 $GIT_DIR,但是,这将解析为 $GIT_DIR/xyzzy。但通常只有各种 *HEAD 名称应该在 $GIT_DIR.)


1好吧好吧,"not just to be pedantic"。 :-)

2有些人会说"very not-helpful",实际上我倾向于同意。

3基本上,git fetch,以及遥控器和 refspecs 的整个概念,是对 Git 的较晚添加,发生在Git 1.5 的时间。在那之前只有一些临时的特殊情况,标签获取就是其中之一,所以它通过特殊代码得到了保护。

4如果有帮助,请将遥控器 Git 视为俚语中的 flasher

要获取特定的标签代码,请尝试创建一个新分支并在其中添加获取标签代码。 我已经通过命令完成了:$git checkout -b newBranchName tagName

为了检出一个 git 标签, 你将执行以下命令

git checkout tags/tag-name -b branch-name

例如下面提到的。

 git checkout tags/v1.0 -b v1.0-branch

查找远程标签:

git ls-remote --tags origin

使用给定的标签消息创建标签

git tag <tag_name> -a -m "tag message"

将单个标签推送到远程

git push origin <tag_name>

将所有标签推送到远程

git push origin --tags

这有点断章取意,但如果你来这里是因为你想像我一样标记特定的提交

这是执行此操作的命令:-

示例:

git tag -a v1.0 7cceb02 -m "Your message here"

其中 7cceb02 是提交 ID 的开始部分。

然后您可以使用 git push origin v1.0 推送标签。

您可以 git log 显示当前分支中的所有提交 ID。

当我想要标签中的代码时,我可能不想创建分支(通常,如果我要对其进行热修复,我只需要一个完整的分支)。

要暂时将您的分支返回到标记处的代码,请执行以下操作:

git reset --hard tags/1.2.3

我可以根据需要简单地使用它,然后在完成后返回分支的 HEAD,使用简单的 git pull