一尘不染

如何协调分离的 HEAD 与 master/origin?

git

我是 Git 分支复杂性的新手。我总是在一个分支上工作并提交更改,然后定期推送到我的远程源。

最近的某个地方,我对一些文件进行了重置以使它们脱离提交暂存状态,后来又做了一个rebase -i以摆脱最近的几个本地提交。现在我处于一种我不太了解的状态。

在我的工作区域中,git log完全显示了我的期望——我在正确的火车上,有我不想消失的提交,还有新的提交,等等。

但是我只是推送到远程存储库,有什么不同 - 我在 rebase 中杀死的几个提交被推送了,而本地提交的新提交不存在。

我认为“master/origin”与 HEAD 是分离的,但我不是 100% 清楚这意味着什么,如何使用命令行工具对其进行可视化,以及如何修复它。


阅读 204

收藏
2022-02-19

共1个答案

一尘不染

HEAD 是当前签出提交的符号名称。当 HEAD 未分离时(“正常” 1情况:您已签出一个分支),HEAD 实际上指向一个分支的“ref”,而该分支指向提交。HEAD 因此被“附加”到一个分支上。当您进行新的提交时,HEAD 指向的分支会更新为指向新的提交。HEAD 自动跟随,因为它只是指向分支。

  • git symbolic-ref HEAD产生refs/heads/master
    名为“master”的分支被签出。
  • git rev-parse refs/heads/masteryield17a02998078923f2d62811326d130de991d1a95a
    该提交是主分支的当前提示或“头部”。
  • git rev-parse HEAD也产生17a02998078923f2d62811326d130de991d1a95a
    这就是“符号参考”的含义。它通过其他一些引用指向一个对象。
    (符号引用最初是作为符号链接实现的,但后来更改为带有额外解释的普通文件,以便它们可以在没有符号链接的平台上使用。)

我们有HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

当 HEAD 分离时,它直接指向一个提交,而不是通过分支间接指向一个提交。您可以将分离的 HEAD 视为位于未命名的分支上。

  • git symbolic-ref HEAD失败了fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEADyield17a02998078923f2d62811326d130de991d1a95a
    因为它不是符号引用,所以它必须直接指向提交本身。

我们有HEAD17a02998078923f2d62811326d130de991d1a95a

使用分离的 HEAD 时要记住的重要一点是,如果它指向的提交是未引用的(没有其他 ref 可以到达它),那么当您签出其他一些提交时,它将变得“悬空”。最终,此类悬空提交将通过垃圾收集过程进行修剪(默认情况下,它们至少保留 2 周,并且可能会通过 HEAD 的 reflog 引用而保留更长时间)。

1 使用分离的 HEAD 进行“正常”工作是完全可以的,您只需要跟踪您正在做的事情以避免不得不从 reflog 中删除丢弃的历史记录。


交互式 rebase 的中间步骤是使用分离的 HEAD 完成的(部分是为了避免污染活动分支的 reflog)。如果您完成了完整的 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如果远程分支无法“快速转发”到新提交(即您删除,或重写了一些现有提交,或以其他方式重写了一些历史记录),您可能需要添加到此命令的末尾以进行推送。

如果您正在进行 rebase 操作,您可能应该清理它。您可以通过查找目录来检查变基是否正在进行中.git/rebase-merge/。您可以通过删除该目录来手动清理正在进行的变基(例如,如果您不再记得活动变基操作的目的和上下文)。通常您会使用git rebase --abort,但这会进行一些您可能希望避免的额外重置(它将 HEAD 移回原始分支并将其重置回原始提交,这将撤消我们在上面所做的一些工作)。

2022-02-19