为什么我在签出最近的提交后有一个分离的 HEAD



>最近,在 git 存储库中工作时,我想查看旧提交(68cce45)的代码,所以我做了

git checkout 68cce45

查看更改后,我想返回到存储库的当前版本并继续工作。由于2bcfd11是最近的提交,我做了

git checkout 2bcfd11

然后我做了一些更改并做了

git add *

然后

git status

这给了我警告:HEAD detached at 2bcfd11.

我很困惑。我可以理解如果我签出的最后一次提交是几个版本前,为什么我会处于"分离的 HEAD 状态"。但是由于我签出的最后一次提交是存储库的最新版本,那么为什么我会处于分离的 HEAD 状态?HEAD 现在不是指向存储库的"顶部"吗?

为什么我会处于分离的HEAD状态?

因为您签出了提交而不是分支。签出任何提交 - 你处于分离的HEAD状态。

HEAD 现在不是指向存储库的"顶部"吗?

git真的不知道它是否是顶部。您必须通过签出分支来向git解释这一点:

git checkout master

现在git知道它是一个已知分支的负责人。分离的 HEAD 问题的结束。

稍微扩展一下博士的答案:在 Git 中,HEAD,像这样拼写为大写字母,1是一个非常特殊的名字。HEAD可以附加(到分支名称),也可以分离。 在这两种情况下,Git 都能够告诉你正在使用哪个提交

git rev-parse HEAD

将打印一些哈希 ID。 但只有当HEAD附加到分支名称时,Git 才能告诉你正在使用哪个分支名称

git rev-parse --symbolic-full-name HEAD
git symbolic-ref HEAD

如果您位于分支上,两者都会为您提供当前分支的名称(前缀为refs/heads/)。 如果您处于分离的 HEAD 模式,前者只会打印HEAD,后者会产生错误:

$ git checkout --detach master
HEAD is now at 7c20df84bd Git 2.23-rc1
Your branch is up to date with 'origin/master'.
$ git rev-parse --symbolic-full-name HEAD
HEAD
$ git symbolic-ref HEAD
fatal: ref HEAD is not a symbolic ref

许多形式的git checkout分离HEAD。 一些表格将附加它。 使用git checkoutbranch-name附加它,同时(如上所示)您可以添加--detach以确保它变为或保持分离状态。

使用原始哈希 ID(如7c20df84bd)始终会导致分离的 HEAD,即使有一个或多个分支名称标识此特定提交也是如此。

请注意,您可以拥有任意数量的分支名称,这些名称都标识相同的提交:

$ for i in m1 m2 m3; do git branch $i master; done
$ git checkout m1
Switched to branch 'm1'
$ git rev-parse HEAD
7c20df84bd21ec0215358381844274fa10515017
$ git checkout m2
Switched to branch 'm2'
$ git rev-parse HEAD
7c20df84bd21ec0215358381844274fa10515017

如果我明确检查出7c20df84bd21ec0215358381844274fa10515017,您希望 Git 使用四个名称中的哪一个——m1m2m3master? 但它不使用它们中的任何一个:如果你想让它使用一个名称,你必须自己提供一个名称:

$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

之后,我们可以删除额外的名称,以便提交7c20df84bd21ec0215358381844274fa10515017仅在master的顶端打开,而不是同时在四个分支的顶端

$ for i in m1 m2 m3; do git branch -d $i; done
Deleted branch m1 (was 7c20df84bd).
Deleted branch m2 (was 7c20df84bd).
Deleted branch m3 (was 7c20df84bd).

请记住,HEAD有两个功能。 它找到当前分支(名称),或者如果分离HEAD则无法执行此操作;并找到当前提交阿拉伯数字你从 Git 得到的答案取决于你问的问题:你想知道分支名称,还是想知道当前的提交哈希 ID?


1在某些系统上,您有时可以用小写字母拼写出来,head,并获得相同的效果。 然而,这在添加的工作树中开始神秘地失败。 最好坚持全大写HEAD,或者如果打字太烦人,单字符@具有相同的特殊含义。

2這也可能失敗,但僅限於特殊狀態。 您处于此状态,位于一个新的完全为空的存储库中,其中您当前的分支名称master,但分支master本身尚不存在。 这是因为分支名称必须包含某个现有的有效提交对象的哈希 ID。 在一个新的、完全空的存储库中,根本没有提交。 因此,不允许存在分支名称。 尽管如此,HEAD附在名称上master.

当你处于这种状态时——Git 的某些部分称之为孤立分支,如在git checkout --orphan中,而另一些部分称其为未出生的分支,如git status所说的那样——你所做的下一次提交会导致分支名称存在。 该名称已经在某个地方(具体来说,存储在HEAD中),但是在首先创建一个有效的提交(其名称可以保存其哈希 ID)之后,提交会将该名称创建为有效的分支名称。

>HEAD是您当前签出的任何提交。可能有也可能没有一个分支(比如master可能)指向HEAD或不指向。当你做git checkout 2bcfd11时,你更新了你的HEAD,但保持分离 - 也就是说,你没有向git表明你想要有一些与之关联的符号名称。如果你有一个指向2bcfd11的分支,你可以git checkout该分支并没事。如果你不这样做,git branch会让你在2bcfd11创建一个分支,使用你想要的任何名称。

使用 Git 2.23(昨天,2019 年 8 月发布),执行git restore

git restore -s <SHA1> -- .

那时你不会有一个分离的HEAD(例如,你留在你当前的分支上,master,但内容不同)。

完成后,您可以通过以下方式恢复正确的工作树:

git restore -s master -- .

相关内容

  • 没有找到相关文章