签出最近的提交后,为什么会有分离的HEAD?

时间:2019-08-18 02:03:35

标签: git git-checkout git-detached-head

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

git checkout 68cce45

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

git checkout 2bcfd11

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

git add *

然后

git status

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

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

4 个答案:

答案 0 :(得分:3)

  

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

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

  

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

git并不真正知道它是否是顶部。您必须通过签出分支来向git进行解释:

git checkout master

现在git知道它是已知分支的头。分离的HEAD问题的结束。

答案 1 :(得分:1)

稍微扩展一下phd's answer:在Git中,HEAD像这样大写, 1 是一个非常特殊的名称。 HEAD可以附加(到分支名称),也可以分离。在这两种情况下,Git都能告诉您您正在使用哪个 commit

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以确保它变得分离或保持分离。

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

请注意,您可以根据需要使用任意多个分支名称​​ all 标识相同提交:

$ 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仅,而不是开头的{em}四个分支都在同一时间。

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


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

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

当您处于这种状态时,Git的某些部分将其称为 orphan分支,例如git checkout --orphan,而其他部分则将其称为 unborn branch ,就像git status所说的那样-您进行的 next 提交会导致分支名称成立。该名称已经存在(具体地,存储在HEAD中),但是在首先创建一个可以保留其哈希ID的有效提交之后,该提交将名称创建为有效的分支名称。 / p>

答案 2 :(得分:0)

HEAD是您当前已签出的所有提交。可能有也可能没有指向master的分支(例如HEAD)。完成git checkout 2bcfd11后,您更新了HEAD,但保持分离状态-也就是说,您并未向git表示您想要与此名称相关联的符号名称。如果您有一个指向2bcfd11的分支,则可以git checkout分支并且可以。如果不这样做,git branch将允许您在2bcfd11处创建一个分支,并使用任意名称。

答案 3 :(得分:0)

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

git restore -s <SHA1> -- .

那时您将没有分离的HEAD(例如,您保留在当前分支上,例如master,但内容不同)。

完成后,可以使用以下方法恢复正确的工作树:

git restore -s master -- .