Answers:
标签用于标记和标记历史记录中的特定提交。
通常用于标记发布点(例如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
A
是一个提交哈希
git checkout tags/<tag_name> -b <branch_name>
确实需要-b <branch_name>
。git checkout tags/<tag_name>
给了我一个超然的头。根据这篇有关分离头的文章,您可以通过临时创建和删除分支来避免分离头。这是相当陌生的工作流程。显然,作为git用户,我需要习惯于创建和删除分支以获取乐趣和获利。
(此答案花了一段时间才写出来,而codeWizard的答案在目的和本质上是正确的,但还不完整,因此无论如何我都会发布它。)
没有所谓的“远程Git标签”。只有“标签”。我指出这一切了不迂腐,1但因为混乱的这个搭配休闲的Git用户带来了极大的交易,Git的文件是不是非常有帮助2至初学者。(尚不清楚混淆是由于文档不佳引起的,还是文档不佳是由于固有的混淆或其他原因而来的。)
这里是 “远程分支”,更恰当地称为“远程跟踪分支”,但值得注意的是,这些其实都是当地实体。但是,没有远程标签(除非您(重新)发明它们)。只有本地标签,因此您需要在本地获取标签才能使用它。
特定提交的名称(Git称为引用)的一般形式是任何以开头的字符串refs/
。一个refs/heads/
以分支开头的字符串;以refs/remotes/
名字开头的字符串,代表一个远程跟踪分支;以及refs/tags/
以标签开头的字符串。名称refs/stash
是隐藏引用(由git stash
;使用;请注意没有尾部的斜杠)。
有迹象表明,不开始一些不寻常的特殊情况名称refs/
:HEAD
,ORIG_HEAD
,MERGE_HEAD
,和CHERRY_PICK_HEAD
特别皆是也可能是指特定的提交(虽然名字HEAD
通常包含分支的名称,即包含)。但通常,引用以开头。ref: refs/heads/branch
refs/
Git所做的一件事是使您感到困惑,因为它允许您省略refs/
,并且经常省略after一词refs/
。例如,您可以省略,refs/heads/
或者refs/tags/
在引用本地分支或标记时-实际上,在签出本地分支时必须省略refs/heads/
!只要结果是明确的,或者正如我们刚刚指出的那样,您就可以在必须这样做的情况下执行此操作。git checkout branch
确实,引用不仅存在于您自己的存储库中,而且还存在于远程存储库中。但是,Git仅允许您在非常特定的时间(即在fetch
和push
操作期间)访问远程存储库的引用。您还可以使用git ls-remote
或git remote show
看到他们,但fetch
和push
有接触的更有趣点。
在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/
)。
正是通过这样的Refspec说origin
的分支成为远程跟踪分支远程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/xyzzy
或refs/tags/xyzzy
。(请注意,这确实适用于git checkout
,但可能是一种意外的方式:git checkout refs/heads/xyzzy
导致分离HEAD检出,而不是分支检出。这就是为什么您只需要注意首先git checkout
将短名称用作分支名的原因:xyzzy
即使标签xyzzy
存在,也要签出分支。如果要签出标签,可以使用refs/tags/xyzzy
。)
因为(作为gitrevisions
注释)Git会尝试,所以您也可以简单地编写以标识已标记的提交。(但是,如果有人设法编写了一个有效的引用命名为,则该解析为。但是通常只有各种名称应位于。)refs/name
tags/xyzzy
xyzzy
xyzzy
$GIT_DIR
$GIT_DIR/xyzzy
*HEAD
$GIT_DIR
1好吧,好吧,“不只是要迂腐”。:-)
2有些人会说“非常无济于事”,实际上,我倾向于表示同意。
3基本上,git fetch
和以及remotes和refspecs的整个概念是对Git的较晚添加,它发生在Git 1.5左右。在此之前,只有一些特殊的特殊情况,而标签获取就是其中之一,因此它通过特殊代码而广为人知。
4如果有帮助,请将远程Git看作是flasher,在,语中是指。
git fetch
只会在给定--tags
arg的情况下获取远程服务器的标签。
--tags
,--no-tags
和默认实际上是相当棘手。默认情况是在要引入的提交中引入不包含的标签。(请参阅2017年1月的编辑。)但是这里也存在故障,现代Git的--tags / --no-tags处理代码再次修订,这可能会导致出现更多特殊情况。
要获取特定的标记代码,请尝试创建一个新的分支,在其中添加标记代码。我已经通过命令完成了:$git checkout -b newBranchName tagName
git checkout A
。是什么A
?您是如何创建的A
?