首先,让我们弄清HEAD是什么,分离后的含义。
HEAD是当前已检出提交的符号名称。如果未分离HEAD(“正常” 1情况:您已签出分支),则HEAD实际上指向分支的“ ref”,而分支则指向提交。HEAD因此“附加”到分支。当您进行新提交时,HEAD指向的分支将更新为指向新提交。HEAD自动跟随,因为它仅指向分支。
git symbolic-ref HEAD
产生refs/heads/master
签出名为“ master”的分支。
git rev-parse refs/heads/master
yield 17a02998078923f2d62811326d130de991d1a95a
提交是master分支的当前提示或“头部”。
git rev-parse HEAD
也会产生17a02998078923f2d62811326d130de991d1a95a
这就是“符号引用”的含义。它通过其他一些引用指向一个对象。
(符号引用最初是作为符号链接实现的,但后来更改为带有额外解释的纯文件,以便可以在没有符号链接的平台上使用。)
我们有HEAD
→交通refs/heads/master
→交通17a02998078923f2d62811326d130de991d1a95a
分离HEAD时,它直接指向一个提交,而不是通过分支间接指向一个提交。您可以将分离的HEAD视为未命名的分支。
git symbolic-ref HEAD
失败于 fatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
yields 17a02998078923f2d62811326d130de991d1a95a
因为它不是符号引用,所以必须直接指向提交本身。
我们HEAD
→17a02998078923f2d62811326d130de991d1a95a
对于分离的HEAD要记住的重要一点是,如果指向它的提交未被引用(其他引用无法到达它),那么当您签出其他提交时,它将变成“悬挂”。最终,此类悬空的提交将在垃圾回收过程中被修剪(默认情况下,它们至少保留2周,并且可能被HEAD的reflog引用保留更长时间)。
1
使用分离的HEAD进行“正常”工作是完全可以的,您只需跟踪自己在做什么,以避免不得不从reflog中删除掉历史记录。
交互式基础的中间步骤是通过分离的HEAD完成的(部分是为了避免污染活动分支的引用日志)。如果您完成了完整的rebase操作,它将使用rebase操作的累积结果更新您的原始分支,并将HEAD重新附加到原始分支。我的猜测是您永远不会完全完成变基过程。这将使您留下一个分离的HEAD,指向由rebase操作最近处理的提交。
为了从您的情况中恢复过来,您应该创建一个分支,该分支指向分离的HEAD当前指向的提交:
git branch temp
git checkout temp
(这两个命令可以缩写为git checkout -b temp
)
这会将您的HEAD重新连接到新temp
分支。
接下来,您应该将当前提交(及其历史记录)与预期在其上进行操作的普通分支进行比较:
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp
(您可能要尝试使用日志选项:添加-p
,不--pretty=…
显示整个日志消息等)。
如果您的新temp
分支看起来不错,则可能需要更新(例如)master
以指向它:
git branch -f master temp
git checkout master
(这两个命令可以缩写为git checkout -B master temp
)
然后,您可以删除临时分支:
git branch -d temp
最后,您可能需要推送重新建立的历史记录:
git push origin master
--force
如果无法将远程分支“快速转发”到新的提交(例如,您删除或重写了一些现有的提交,或以其他方式重写了一些历史记录),则可能需要在此命令的末尾添加以推送。
如果您正在执行变基操作,则可能应该清理它。您可以通过查找目录来检查是否正在执行重新设置基准.git/rebase-merge/
。您可以通过删除目录来手动清理进行中的重新配置(例如,如果您不再记得活动的重新配置操作的目的和上下文)。通常,您会使用git rebase --abort
,但是这样做可能会避免一些额外的重置操作(它将HEAD移回原始分支并将其重置为原始提交,这将撤消我们上面所做的一些工作)。