[英]Detached HEAD on same commit as main?
我不太确定在这种情况下我是如何获得我的存储库的,这甚至不再是一个问题,但我想了解发生了什么,所以下次我不会感到如此迷茫。
拉动时,我被警告说我处于分离的 HEAD 状态。 git status
显示如下(截图):
HEAD detached at 44422b7
所以我跑了git log
来找出我离 main 有多远,它显示了(截图):
commit 44422b74b6826291479ee7a17fe18bb4acca6355 (HEAD, main)
这对我来说没有多大意义,因为我似乎与主分支在同一个提交中,但是为了解决问题,我运行了git checkout main
,然后显示下一个git log
(截图),
commit 44422b74b6826291479ee7a17fe18bb4acca6355 (HEAD -> main)
一切都开始按照我最初的预期工作。
所以我试图理解git log
在我第一次和第二次运行它时显示的区别(带有箭头的那个与只有一个逗号的那个),也许了解我是如何遇到这种情况的第一名。
感谢我能得到的任何帮助。
分支是指向提交的标签。
HEAD 总是指向当前签出的提交。
commit 44422b74b6826291479ee7a17fe18bb4acca6355 (HEAD, main)
commit 44422b74b6826291479ee7a17fe18bb4acca6355 (HEAD -> main)
两者都说你在提交 44422b74b6826291479ee7a17fe18bb4acca6355。 两者都说 HEAD 和该提交的要点。 但是HEAD -> main
说 main 是当前签出的分支。
当您运行git commit
时,会创建一个新的提交,并且当前签出的分支和 HEAD 会被移至它。
可能没有签出分支,这是一个分离的 HEAD 状态。 在这种情况下,当你git commit
只有 HEAD 移动。 没有分支正在跟踪您的提交。 如果你git checkout
或git switch
away,将(几乎)没有任何东西提到那些分离的提交。
有很多方法可以进入分离的 HEAD 状态,最基本的是检查提交 ID。 git checkout 4ba97c6ffc71f88a4de4ed88b188dbec2e5ff325
。
您可以通过检查分支来摆脱分离的 HEAD 状态,就像您所做的那样。 或者你可以在你所在的地方建立一个新的分支。
确保使用git switch main
,而不是git checkout main
。
通过使用git switch
,您可以降低以分离的 HEAD结尾的风险,因为您会收到错误消息(切换到提交或远程分支时)
fatal: a branch is expected, got remote branch 'origin/master'
您需要显式添加--detach
选项才能得到一个分离的 HEAD。
这实际上是两个独立的问题:
试图了解 git log 在我第一次和第二次运行它时显示的内容之间的区别(带有箭头的那个与只有一个逗号的那个),
首先要了解我是如何陷入这种境地的。
问题 2 的答案是为什么我的 Git 存储库进入了分离的 HEAD 状态?
问题 1 的答案更简单:第一个显示 detached-HEAD 状态,第二个带有箭头的显示attached-HEAD 状态。 但是我们可以稍微解释一下:特别是“分离 HEAD”的整个概念首先有点奇特。 不过,在我们描述它之前,我们必须知道附加的 HEAD 是什么! 从某种意义上说,它是显而易见的——它与分离的 HEAD 相反——但这只是循环推理。 我们需要一些更基本的东西,这在于Git 如何找到提交。
首先,请记住每个 Git 提交都有一个唯一的哈希 ID:
commit 44422b74b6826291479ee7a17fe18bb4acca6355
那一大串难看的字母和数字是一个数字,用十六进制表示。 (十进制是 389687007142770230305517186390235637298437448533,这实际上并没有更好。😀事实上,Git 必须使用十六进制或二进制,因为它在数据库中通过前缀查找这些信息的方式,部分使用了各种大小的 2 次幂。)此哈希 ID 用作简单键值数据库中的键; 该值是提交的内部 Git 表示。
所以 Git需要这个提交哈希 ID 才能找到这个提交。 您必须为 Git 提供哈希 ID:这是 Git 查找提交的唯一方法。 但是谁想一遍又一遍地输入44422b74b6826291479ee7a17fe18bb4acca6355
呢? 你甚至会做对吗? 如果你可以只说main
并且 Git 可以在辅助键值存储中查找main
——或者,技术上, refs/heads/main
——并找到44422b74b6826291479ee7a17fe18bb4acca6355
怎么办? 那不是更好吗?
是的,它实际上更好,这就是我们所做的:我们输入main
或v1.2
或origin/develop
,Git 在这个辅助数据库中查找它以获取原始哈希 ID。 从那里,Git 找到我们想要的提交。
当您“在分支上”时,正如git status
所说,这意味着您所做的每个新提交都会更新当前分支名称。 因此,如果您on branch main
并且您进行了新的提交并且其哈希 ID 为a123456...
或其他任何内容,Git 将存储新提交的哈希 ID a123456...
或其他名称,名称为main
。 (旧的 commit-hash-ID 44422b74b6826291479ee7a17fe18bb4acca6355
- 进入新的提交,因此它现在是倒数第二个提交。)
反过来,这意味着 Git 需要始终知道哪个分支名称是它应该在您进行新提交时更新的名称。 为了记住该分支名称,Git 将特殊名称HEAD
“附加”到分支名称。
(当前的实现是 Git 将ref: refs/heads/main
写入.git/HEAD
。但是,这个实现在未来可能会发生变化。当前的实现已经与之前的不同,并且已经有所改变处理添加的工作树,因为现在它有时根本不是.git/HEAD
:那只是用于主工作树。)
附加的 HEAD是指 HEAD 包含分支的名称。 HEAD 中包含的分支名称是当前分支。 分支名称本身,在充满名称到哈希 ID 映射的数据库中,包含当前提交的哈希 ID。 所以HEAD
提供了两条信息:
要分离HEAD,Git 只需将某个提交(任何现有提交)的原始哈希 ID 写入HEAD
。 现在.git/HEAD
包含一个原始哈希 ID,没有当前分支名称,但仍然有一个当前提交哈希 ID 。 只是HEAD
现在直接持有了。 无需在名称数据库中查找名称。
你所做的一切仍然和以前一样工作:特别是,如果你创建一个新的提交,新的提交会连接(向后,就像提交一样)到你创建新提交时的当前提交; 现在新的提交就是当前的提交,即 Git 已将其哈希 ID 存储在HEAD
中。
如果您确实进行了这样的提交并运行git log
,您将看到:
commit a123456... (HEAD)
[your new commit]
commit 44422b74b6826291479ee7a17fe18bb4acca6355 (main)
[your old commit]
由于git log
从当前提交开始并向后工作,因此一次提交一个。 但是由于您没有创建新的,因此名称HEAD
和名称main
均表示“提交 44422b74b6826291479ee7a17fe18bb4acca6355”,因此您得到:
commit 44422b74b6826291479ee7a17fe18bb4acca6355 (HEAD, main)
附加HEAD
后,Git 会使用该向前箭头符号打印它(因为 Git 2.10:在 2.10.0 之前,Git 打印HEAD, main
两种情况)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.