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


522

当我签出远程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 tag命令时可以找到remote_tag_name。

Answers:


1152

让我们从解释git中的标签开始

在此处输入图片说明

标签用于标记和标记历史记录中的特定提交
通常用于标记发布点(例如v1.0等)。

尽管标签看起来可能类似于分支,但是标签不会改变。它直接指向历史记录中的特定提交

在此处输入图片说明


如果标签不在您的存储库中,您将无法检出标签,因此,首先,您必须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>

而不是origin使用tags/前缀。


在此示例中,您有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 commit一样添加元数据:
名称,电子邮件,日期,评论和签名

在此处输入图片说明

如何删除标签?

# delete any (local) given tag
$ git tag -d <tag name>

# 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 通过在clone命令中添加来支持浅层克隆,因此--branch我们可以使用标签名代替分支名。Git知道如何将给定的SHA-1“翻译”为相关的提交

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

git clone --branch =

--branch 也可以获取标签并在结果存储库中的提交时分离HEAD。


如何推送标签?

git push --tags

推送所有标签:

# Push all tags
$ git push --tags 

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

为什么?-建议使用,refs/tags因为有时标签可以与分支具有相同的名称,而简单的git push会推送分支而不是标签

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

git push --follow-tags

这个标志--follow-tags既推送提交,也推送既是两个的标签

  • 带注释的标签(因此您可以跳过本地/临时构建标签)
  • 来自当前分支(位于历史记录上)的可到达标签(祖先)

在此处输入图片说明

在Git 2.4中,您可以使用配置进行设置

$ git config --global push.followTags true

备忘单: 在此处输入图片说明



3
很好 git checkout A。是什么A?您是如何创建的A
Honey

3
@CodeWizard不错的流程图!您使用哪个软件生产?
Giovanni Lovato

4
@Honey A是一个提交哈希
Alex Baklanov

2
@GiovanniLovato流程图是第三方的。指向该图像的链接是backlog.com/git-tutorial/img/post/stepup/…,该页面的backlog.com/git-tutorial/stepup/stepup4_1.html该网站称为Git傻瓜入门指南(backlog) .com)。
乔治

2
值得注意的是git checkout tags/<tag_name> -b <branch_name>确实需要-b <branch_name>git checkout tags/<tag_name>给了我一个超然的头。根据这篇有关分离头的文章,您可以通过临时创建和删除分支来避免分离头。这是相当陌生的工作流程。显然,作为git用户,我需要习惯于创建和删除分支以获取乐趣和获利。
icc97 '18

194

(此答案花了一段时间才写出来,而codeWizard的答案在目的和本质上是正确的,但还不完整,因此无论如何我都会发布它。)


没有所谓的“远程Git标签”。只有“标签”。我指出这一切了不迂腐,1但因为混乱的这个搭配休闲的Git用户带来了极大的交易,Git的文件是不是非常有帮助2至初学者。(尚不清楚混淆是由于文档不佳引起的,还是文档不佳是由于固有的混淆或其他原因而来的。)

这里 “远程分支”,更恰当地称为“远程跟踪分支”,但值得注意的是,这些其实都是当地实体。但是,没有远程标签(除非您(重新)发明它们)。只有本地标签,因此您需要在本地获取标签才能使用它。

特定提交的名称(Git称为引用)的一般形式是任何以开头的字符串refs/。一个refs/heads/以分支开头的字符串;以refs/remotes/名字开头的字符串,代表一个远程跟踪分支;以及refs/tags/以标签开头的字符串。名称refs/stash是隐藏引用(由git stash;使用;请注意没有尾部的斜杠)。

有迹象表明,不开始一些不寻常的特殊情况名称refs/HEADORIG_HEADMERGE_HEAD,和CHERRY_PICK_HEAD特别皆是也可能是指特定的提交(虽然名字HEAD通常包含分支的名称,即包含)。但通常,引用以开头。ref: refs/heads/branchrefs/

Git所做的一件事是使您感到困惑,因为它允许您省略refs/,并且经常省略after一词refs/。例如,您可以省略,refs/heads/或者refs/tags/在引用本地分支或标记时-实际上,在签出本地分支时必须省略refs/heads/!只要结果是明确的,或者正如我们刚刚指出的那样,您就可以在必须这样做的情况下执行此操作。git checkout branch

确实,引用不仅存在于您自己的存储库中,而且还存在于远程存储库中。但是,Git仅允许您在非常特定的时间(即在fetchpush操作期间)访问远程存储库的引用。您还可以使用git ls-remotegit remote show看到他们,但fetchpush有接触的更有趣点。

参考规格

fetch和期间push,Git使用字符串,它调用refspecs在本地和远程存储库之间传输引用。因此,正是在这些时候,并且通过refspecs,两个Git存储库可以彼此同步。姓名同步后,即可使用与远程用户相同的名称。fetch不过,这里有一些特殊的魔术,它会影响分支名称和标记名称。

您应该考虑git fetch指导您的Git调用(或发短信)另一个Git(即“远程”)并与之进行对话。在此对话的开始,远程列出了它的所有引用:中的所有内容refs/heads/和中的所有内容refs/tags/,以及它具有的任何其他引用。您的Git会扫描这些分支,并(基于通常的获取refspec)重命名其分支。

让我们看一下名为的远程对象的常规refspec origin

$ 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”标志,即,将更新您的远程跟踪分支以匹配远程分支的名称,而不管使其匹配所需的时间。(没有+,分支更新仅限于“快进”更改,而自Git版本1.8.2以来,标记更新仅被忽略,因此之前未应用相同的快进规则。)

标签

但是标签呢?没有针对它们的refspec-至少不是默认情况下。您可以设置一个,在这种情况下refspec的形式由您决定;或者你可以跑步git fetch --tags。使用--tags具有添加refs/tags/*:refs/tags/*到refspec的作用,即使用它会带走所有标签(但是,如果您已经具有该名称的标签,则不会更新您的标签,无论遥控器的标签说的是 Edit,2017年1月:从Git 2.10开始)测试表明,--tags从ref的标签中强制更新了标签,就像refspec读取一样+refs/tags/*:refs/tags/*;这可能与早期版本的Git有所不同。

请注意,这里没有重命名:如果remote origin具有tag xyzzy,而您没有,则您git fetch origin "refs/tags/*:refs/tags/*"将被refs/tags/xyzzy添加到存储库(指向与远程相同的提交)。如果您使用,+refs/tags/*:refs/tags/*则您的标签xyzzy(如果有)被中的替换origin。也就是说,+refspec上的force标志意味着“用我的Git从其Git获得的值替换我的参考值”。

提取期间自动标记

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

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

底线

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

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

当您需要限定名称时

我上面提到的,你可以省略refs/几乎总是和refs/heads/refs/tags/等大部分的时间。但是什么时候不能呢?

完整(或接近完整反正)答案是gitrevisions文件。Git将使用链接中给出的六步顺序将名称解析为提交ID。奇怪的是,标记会覆盖分支:如果有一个标记xyzzy和一个branch 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/nametags/xyzzyxyzzyxyzzy$GIT_DIR$GIT_DIR/xyzzy*HEAD$GIT_DIR


1好吧,好吧,“不只是要迂腐”。:-)

2有些人会说“非常无济于事”,实际上,我倾向于表示同意。

3基本上,git fetch和以及remotes和refspecs的整个概念是对Git的较晚添加,它发生在Git 1.5左右。在此之前,只有一些特殊的特殊情况,而标签获取就是其中之一,因此它通过特殊代码而广为人知。

4如果有帮助,请将远程Git看作是flasher,在,语中是指。


很棒的文章。一个小巧的尼特:git fetch只会在给定--tagsarg的情况下获取远程服务器的标签。
cweek18年

@cweekly:的行为--tags--no-tags和默认实际上是相当棘手。默认情况是在要引入的提交中引入不包含的标签。(请参阅2017年1月的编辑。)但是这里也存在故障,现代Git的--tags / --no-tags处理代码再次修订,这可能会导致出现更多特殊情况。
torek '18 -10-26

1

为了签出git标签,您将执行以下命令

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

例如如下所述。

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

要获取所有标签,请使用以下命令

git fetch --all --tags

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.