在 Git 上签出标签

  • 本文关键字:标签 Git git git-tag
  • 更新时间 :
  • 英文 :


我正在浏览一些 git 内部,遇到了标签以及它们在内部的存储方式。在 Git SCM 站点中,我发现了以下内容:

签出标签

您无法真正签出 Git 中的标签,因为它们无法移动 周围。如果要将存储库的一个版本放入您的 看起来像特定标签的工作目录,您可以创建一个新的 使用 git checkout -b [分支名称] [标记名称] 的特定标记处分支:

git checkout -b version2 v2.0.0

切换到新的分支"版本 2">

当然,如果您这样做并执行提交,则您的版本2分支将是 与您的 v2.0.0 标签略有不同,因为它会向前移动 对于您的新更改,请务必小心。

我有以下疑问:

  1. 为什么我们不能签出标签?我们不能遍历 Git TAG 来HEAD指向标签指向的提交吗?
  2. 我们是否可以创建一个新的提交,然后指向提交 由标签指向父级?
  3. 据说如果我们从标签创建一个新分支并提交,它会略有不同。他们在谈论什么区别?新提交(假设没有任何变化)不会将标记的提交称为其父提交,而其他所有内容(树和斑点)保持不变吗?

谢谢。

编辑:
我指的是HEAD和标签指向不同提交的情况。

为什么我们不能签出标签?

我们可以!

我们不能遍历 Git TAG 以使 HEAD 指向标签指向的提交吗?

是的,我们可以做到这一点(尽管严格来说,我们甚至不需要太多(如果有的话):提交是快照,所以一旦我们到达正确的快照,我们就完成了,标签通常需要零个或一个中间步骤才能到达提交)。

HEAD文件(.git名为HEAD的实际文件)更典型的状态是它包含分支的名称,而不是提交的 ID。 这种模式没有太多正式的名称,但我称之为"在分支上",以与其他模式形成对比。

.git/HEAD直接指向某个提交(通过包含其哈希 ID)时,我们得到的模式,正如 CodeWizard 在注释中提到的,称为"分离的 HEAD"。 由于.git/HEAD不再包含分支的名称,我们现在没有分支——或者,等效地,在某种未命名的分支上,我们可以在其中使用@符号(从 Git 版本 1.8.5 开始)来命名它,或者拼写出单词HEAD。 当然,HEAD是一个好名字;例如,Git 会在我们再次运行git checkout master时立即覆盖.git/HEAD文件的内容,然后我们将不再将哈希 ID 存储在任何地方。

我们可以创建一个新的提交,然后将指向标签指向的提交作为父级吗?

英语在这里有点模棱两可,但我认为图表更清楚地表明答案是"是":

initially: on branch `master` with commit `H` as the current commit
...--F--G     <-- tag: v2.0.0

H   <-- master (HEAD)

在这里,将H点提交回去提交G;提交G点以提交F;依此类推。 名为master的分支指向提交H,标记名称v2.0.0指向提交G(如果是轻量级标记,则直接提交,或者通过一个带注释的标记对象,如果是带注释的标记)。

After `git checkout v2.0.0`:
...--F--G     <-- HEAD, tag: v2.0.0

H   <-- master

.git/HEAD文件现在包含提交G的哈希 ID

If we make a new commit now:
I   <-- HEAD
/
...--F--G     <-- tag: v2.0.0

H   <-- master

正如您所建议的,新提交I将提交G作为其父级。.git/HEAD文件现在包含提交I的哈希 ID

据说如果我们从标签创建一个新分支并提交,它会略有不同。他们在谈论什么区别?新提交(假设没有任何变化)不会将标记的提交称为其父提交,而其他所有内容(树和斑点)保持不变吗?

提交内容将是相同的,但提交图的绘制会略有变化。 这是新的图形绘图,从相同的起点开始,但使用git checkout -b version2 v2.0.0作为中间步骤。

initially: on branch `master` with commit `H` as the current commit
...--F--G     <-- tag: v2.0.0

H   <-- master (HEAD)

After `git checkout -b version2 v2.0.0`:
...--F--G     <-- version2 (HEAD), tag: v2.0.0

H   <-- master

If we make a new commit now:
I   <-- version2 (HEAD)
/
...--F--G     <-- tag: v2.0.0

H   <-- master

请注意,在本例中(我们"在名为version2的分支上"),当我们进行新提交时,分支名称会随之移动。 当我们不在任何分支上时,在"分离的 HEAD"模式下,新提交只是更新(存储在.git/HEAD中的提交哈希 ID)。 但是,当.git/HEAD包含分支的名称时,这些新提交会更新该分支.git/HEAD文件本身只是继续包含分支的名称。


事实上,这就是"在分支上"的含义:每当.git/HEAD包含分支的名称时,各种操作(特别是包括进行新提交和使用git reset)都会更改分支名称记住的哈希 ID,而不是更改.git/HEAD本身。 每当.git/HEAD包含提交的哈希 ID时,这些相同的操作只会.git/HEAD自身更新。

git checkout命令通常更新.git/HEAD的内容,是少数可以更改存储在.git/HEAD中的分支名称的命令之一。 (我在这里说"通常"git checkout因为它有点像厨房水槽命令,具有各种模式来做奇怪的事情,因为它们与它通常做的主要事情密切相关。 具体来说,如果你在一个分支上,git checkout可以将你放在另一个分支上;如果你不在任何分支上,git checkout可以让你进入一个分支;如果您使用--detach或标签名称或类似名称,git checkout可以将您置于分离的 HEAD 模式;如果您不在任何分支上,git checkout可以更改HEAD指向哪个提交。

(git reset命令可以执行其中的一些操作,但它不会带您进入或离开任何分支。 像git checkout一样,它有点"厨房下沉":它可以做很多事情,如果没有很多文字和几个图表,很难很好地描述这些!

最新更新