Git标签适用于所有分支吗?

20

我正在学习Git标签,但我的以前的背景是在Subversion中,“tags”只是复制品,而不是“真正”的标签...

如果我向Git仓库添加一个标签,它会应用于所有分支还是仅适用于当前分支?

例如,如果我当前有这些分支(git branch -v):

* master deadbeef My master head comment
  dev    baddfeed My def head comment

目前检出的分支是master,如您所见。现在假设我运行git tag -a TAGNAME,那么TAGNAME只适用于deadbeef(master分支)还是baddfeed(dev分支)也适用?

例如,假设我在检出标签之前切换到了dev分支(即不是创建标签的分支):

git checkout dev
git checkout TAGNAME
我会得到一个指向baddfeed的checkout吗?还是检出标签(第二行)会将我切换回主分支(标签创建时所在的位置),然后使我得到一个指向deadbeef的checkout?(或者第三个选项,我对创建和恢复标签的理解太错误或太简单,以至于答案不可能像这两个选项中的一个那么简单?)
此外,如果我使用轻量级标签(git tag TAGNAME)而不是带注释的标签,问题的答案是否会改变?

1
我强烈建议阅读以下内容:http://git-scm.com/book/en/Git-Basics-Tagging和https://www.kernel.org/pub/software/scm/git/docs/git-tag.html。所有的内容都在里面。 - Agis
1
一个标签用于标识单个提交。请参阅Git对象模型 - Greg Bacon
Greg的回答就是你所需要的。标签是没有上下文的单个提交,它们存在于存储库范围的命名空间中。你不会谈论某个标签是否“在”分支上,就像你不会谈论Linux 3.11是否“在”任何分支上一样(显然它将存在于内核的任何分支中!)。 - Andy Ross
3个回答

23

假设你现在在分支myBranch,并创建了一个名为myTag的标签。

-----A-----B-----C-----D-----H-------I-----> master
                       \
                        \
                         \---E----F-----G-----> myBranch
                                        |
                                        myTag

该标记仅在myBranch分支的提交对象上。我也使用过CVS,并且它也会标记修订版本,而不是所有分支(但在CVS中,分支是特殊标记)。我认为不行。

如果您检出myTag,您将进入示例的提交G。您无法在不同的分支上使用相同名称创建标记。如果这样做,您将移动该标记。

对于与此相关的注释标记没有任何区别。

注意:当检出标记时,您将进入“分离的HEAD”模式。除非从检出的标记创建另一个分支,否则您的更改将丢失。


1
谢谢,这让我非常清楚。所以为了关闭循环,如果我在我的OQ中给出了命令序列(即git checkout dev; git checkout TAGNAME),那么我最终会回到_master_分支,在分离模式下检出deadbeef提交(即使它恰好仍然是主分支的头,也会被检出分离);这正确吗? - Dave Lillethun
从技术上讲,“分离头指针”模式下添加的提交并没有被丢失:它们只是没有方便的名称,因此您必须使用原始SHA-1 ID。您可以事后粘贴分支名称。但是,以这种方式进行操作很麻烦。(此外,在一段时间后——默认为90天——如果它们仍然没有“好”的名称,它们将被垃圾回收。) - torek
2
@DaveLillethun 是的。您将再次处于主分支中。即使提交是HEAD,您也将处于分离的HEAD模式。 - Jean Waghetti
@torek 你说得对。我同意你的看法:“那种方法真的很痛苦。” 以防万一,如果有人想知道如何获取这些“丢失”的提交的提交 ID,请使用 git reflog 命令。 - Jean Waghetti

9
简单来说:
如果我在 Git 仓库中添加一个标签,它是应用于所有分支还是只有当前的分支?
在 Git 中,标签仅是指向提交 ID 的别名。当您添加标签时,Git 会将您的标签名称(标签字符串)映射到特定的提交 ID。由于提交 ID 与特定的分支相关(或在合并时与多个分支相关),因此标签仅与该分支(以及任何它合并到的分支)相关。
更多信息请参见这里:http://git-scm.com/book/en/Git-Basics-Tagging#Creating-Tags

9
阅读问题和您的评论后,我认为您困惑的基本点是在 git(与其他系统相比)中“处于分支状态”是什么意思。
在 git 中,git checkout 操作检出某个特定的提交 [但请参阅脚注1]。它还设置了特殊名称 HEAD,使其指向该特定提交。但是:HEAD 可以有两种不同的方式指定一个特定的提交。它可以是:
按 ID(这是不寻常的情况),或
通过间接引用分支名称(这是更常见的情况)。
如果您执行 git checkout branchname,则 git 设置第二种常规情况。然后,如果您 cat .git/refs/HEAD,则会发现它包含字面字符串 ref:,后跟 refs/heads/branchname [2]。这就是“处于分支上”的含义:您已经检出了分支名称所指向的提交,但同时,HEAD 是一个“符号参考”。如果您进行新更改并提交它们,git 将创建新的提交,然后“剥离”分支标签便条并将其粘贴到刚刚添加的新提交上。这将“移动分支”到新添加的末端,并且您仍然“处于分支上”。
另一方面,如果您执行 git checkout tagname,则 git 设置第一种不寻常情况。如果您按 SHA-1 ID(那些 ea56709… 样式的字符串)检出,它也会这样做。在这种情况下,HEAD 的文件只有字面 SHA-1 ID。在此状态下,如果您进行新的提交,则会像往常一样添加,但不会更改粘贴分支标签的便条。您不“处于分支上”;HEAD 不是“符号参考”。
关于实际标签本身,它们仅仅是提交的名称。但等等,分支名称不就是这个吗?是的!分支名称和标签名称之间的区别在于,分支名称预计会移动,并且 git 将在“处于分支状态”时自动移动它。标签名称“不预计移动”[3],不会自动移动。
脚注:
[1] 仅为了混淆事情(或因为某些人认为 git 的用户界面是“邪恶的”:-)),当您要求它检出特定路径名时,有时会发生 git checkout 不会更改 HEAD 的情况。
[2] 在非常旧的git版本中,git使用符号链接而不是ref: ...。链接的目标是分支ID文件,例如refs/heads/master或其他文件,因此打开和读取文件会得到提交ID,并且您必须使用lstat来检测“在分支上”。这在Windows上无法工作,并且排除了“打包”引用(.git/packed-refs),因此改为使用ref:

[3] 短语“预期”和“不预期”应提示您提出问题:预期由谁?Git本身对git用户移动标记没有问题,而是使用git的人们(通常是他们编写的脚本)会因此感到困惑。因此,在移动标记之前,请先与共享存储库的其他人员进行核对。


哇,这是我见过的最好的标签解释,谢谢大师。 - Fareed Alnamrouti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接