最近,在git存储库中工作时,我想在旧提交(68cce45
)上查看代码,所以我做了
git checkout 68cce45
查看更改后,我想返回到存储库的当前版本并继续工作。由于2bcfd11
是最近的提交,所以我做了
git checkout 2bcfd11
然后我做了一些更改并做了
git add *
然后
git status
这给了我警告:HEAD detached at 2bcfd11
。
我很困惑。我可以理解,如果我签出的最后一次提交是多个版本之前,为什么会处于“分离的HEAD状态”。但是,由于我签出的最后一次提交是存储库的最新版本,那么为什么我会处于分离的HEAD状态? HEAD现在不是指向存储库的“顶部”吗?
答案 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要使用m1
,m2
,m3
或master
这四个名称中的哪一个?采用?但它不使用任何名称:如果要使用名称,则必须自己提供名称:
$ 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 -- .