协慌网

登录 贡献 社区

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

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

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

在我的工作区域, git log显示了我所期待的 - 我在正确的列车上,我不想要的提交,以及那里的新提交等。

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

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

答案

首先,让我们澄清一下 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
    该提交是主分支的当前提示或 “头”。
  • git rev-parse HEAD也产生17a02998078923f2d62811326d130de991d1a95a
    这就是 “象征性的参考” 意味着什么。它通过其他参考指向一个对象。
    (符号引用最初是作为符号链接实现的,但后来更改为具有额外解释的普通文件,以便它们可以在没有符号链接的平台上使用。)

我们有HEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

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

  • git symbolic-ref HEADfatal: ref HEAD is not a symbolic ref失败fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD产量17a02998078923f2d62811326d130de991d1a95a
    由于它不是符号引用,它必须直接指向提交本身。

我们有HEAD17a02998078923f2d62811326d130de991d1a95a

使用分离的 HEAD 要记住的重要一点是,如果它指向的提交是未引用的(没有其他引用可以到达它),那么当你检查其他提交时它将变成 “悬空”。最终,这些悬空提交将通过垃圾收集过程进行修剪(默认情况下,它们会保留至少 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

(您可能希望尝试使用日志选项:add -p ,leave off --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-merge/ 。您可以通过删除该目录来手动清理正在进行的 rebase(例如,如果您不再记住活动 rebase 操作的目的和上下文)。通常你会使用git rebase --abort ,但这会做一些你可能想要避免的额外重置(它将 HEAD 移回原始分支并将其重置回原始提交,这将撤消我们上面做的一些工作)。

这样做:

git checkout master

或者,如果您要保留更改,请执行以下操作:

git checkout -b temp
git checkout -B master temp

我遇到了这个问题,当我读到最高投票答案:

HEAD 是当前签出的提交的符号名称。

我想:啊哈!如果HEAD是为 currenlty 结账符号名提交,我可以调和这对master通过衍合靠在master

git rebase HEAD master

这个命令:

  1. 检查出master
  2. HEAD的父提交标识回HEADmaster分开的点
  3. master之上播放那些提交

最终结果是所有在HEAD但不是master中的提交都是mastermaster仍然检查出来。


关于遥控器:

我在 rebase 中杀死的几个提交被推了出来,而那些在本地提交的新提交不在那里。

无法再使用您的本地历史记录快速转发远程历史记录。您需要强制推送( git push -f )来覆盖远程历史记录。如果您有任何协作者,通常有必要与他们协调,以便每个人都在同一页面上。

master推送到远程origin ,将更新远程跟踪分支origin/master以指向与master相同的提交。