5

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

git checkout 68cce45

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

git checkout 2bcfd11

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

git add *

进而

git status

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

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

4

4 回答 4

6

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

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

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

git真的不知道是不是顶级。您必须git通过检查一个分支来解释这一点:

git checkout master

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

于 2019-08-18T02:10:19.820 回答
2

稍微扩展一下phd 的答案:在 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 checkout branch-name--detach

使用原始哈希 ID7c20df84bd总是会导致分离的 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

如果我明确签出,您希望 Git 使用7c20df84bd21ec0215358381844274fa10515017四个名称中的哪一个——<code>m1 m2、、、m3或——?master但它没有使用它们:如果您希望它使用名称,则必须自己提供名称:

$ 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分离则找不到;并找到当前提交2 你从 Git 得到的答案取决于你问的问题:你想知道分支名称,还是想知道当前的提交哈希 ID?


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

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

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

于 2019-08-18T05:16:22.747 回答
0

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

于 2019-08-18T02:10:31.090 回答
0

使用 Git 2.23(昨天,2019 年 8 月发布),做一个git restore

git restore -s <SHA1> -- .

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

完成后,您可以使用以下命令恢复正确的工作树:

git restore -s master -- .
于 2019-08-18T06:41:32.463 回答