我正在浏览一些 git 内部结构并遇到标签以及它们如何在内部存储。在 Git SCM site 中,我发现了以下内容:
Checking out Tags
You can’t really checkout a tag in Git, since they can’t be moved around. If you want to put a version of your repository in your working directory that looks like a specific tag, you can create a new branch at a specific tag with git checkout -b [branchname] [tagname]:
git checkout -b version2 v2.0.0
Switched to a new branch 'version2'
Of course if you do this and do a commit, your version2 branch will be slightly different than your v2.0.0 tag since it will move forward with your new changes, so do be careful.
我有以下疑问:
HEAD
指向tag 指向的提交吗? 由标记指向父项?
谢谢你。
编辑:
我指的是 HEAD 和标签指向不同提交的情况。
最佳答案
Why can't we check out tags?
我们可以!
Can't we traverse the Git TAG to make HEAD point to the commit pointed to by the tag?
是的,我们可以做到这一点(不过,严格地说,如果有任何遍历,我们甚至不需要太多:提交是快照,因此一旦我们到达正确的位置,我们就完成了,并且标签通常需要零个或一个中间步骤到达提交)。
HEAD
文件(它是 .git
中名为 HEAD
的实际文件)的更典型状态是它包含分支的名称,而不是提交的 ID。这种模式没有太多正式的名称,但我称之为“在分支上”,以与其他模式进行对比。当
.git/HEAD
直接指向某个提交(通过包含其哈希 ID)时,我们获得的模式是 as CodeWizard mentioned in a comment ,称为“分离的 HEAD”。由于 .git/HEAD
不再包含分支的名称,我们现在不在任何分支上——或者等效地,在某种未命名的分支上,我们可以使用 @
符号(自 Git 1.8.5 版起)来命名它,或者通过拼出单词 HEAD
。当然 HEAD
是个好名字;只是,例如,只要我们再次运行 .git/HEAD
,Git 就会覆盖 git checkout master
文件的内容,然后我们将不再将哈希 ID 存储在任何地方。Can we create a new commit which will then point to the commit pointed to by tag as the parent?
英语在这里有点模棱两可,但我认为一张图更清楚地表明答案是"is":
initially: on branch `master` with commit `H` as the current commit
...--F--G <-- tag: v2.0.0
\
H <-- master (HEAD)
这里,commit
H
指向commit 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。It is said that if we create a new branch from the tag and commit, it'll be slightly different. What difference are they talking about? Won't the new commit (assuming nothing has changed) refer to the tagged commit as its parent with everything else (trees & blobs) remaining the same?
提交内容将是相同的,但提交图的绘制会有所改变。这是新的图形绘制,从相同的起点开始,但使用
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”模式下,新提交只会更新(存储在其中的提交哈希 ID) .git/HEAD
。但是当 .git/HEAD
包含分支的名称时,这些新提交会更新该分支。 .git/HEAD
文件本身只是继续包含分支的名称。事实上,这就是“在分支上”的含义:每当
.git/HEAD
包含分支名称时,各种操作——特别是包括进行新提交和使用 git reset
——更改分支名称记住的哈希 ID,而不是更改.git/HEAD
本身。每当 .git/HEAD
包含提交的哈希 ID 时,这些相同的操作只会更新 .git/HEAD
本身。git checkout
命令通常更新 .git/HEAD
的内容,是少数可以更改 .git/HEAD
中存储的分支名称的命令之一。 (我在这里说“通常”是因为 git checkout
有点像 kitchen-sink command ,有各种模式可以做奇怪的事情,只是因为它们与它通常做的主要事情密切相关。)具体来说,如果你在一个分支上,git checkout
可以把你放在一个不同的分支上;如果您不在任何分支上,git checkout
可以让您进入一个分支;如果您使用 --detach
或标签名称或类似名称,git checkout
可以让您进入分离的 HEAD 模式;如果您不在任何分支上,git checkout
可以更改 HEAD
指向的提交。(
git reset
命令可以做一些这样的事情,但它不会带你进入或离开任何分支。像 git checkout
一样,它有点“厨房下沉”:它可以做很多事情,很难很好地描述这些没有太多的文字和几个图表!)
关于git - 在 Git 上 check out 标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44903176/