我是 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
git rev-parse refs/heads/master
yield 17a02998078923f2d62811326d130de991d1a95a
git rev-parse HEAD
也产生17a02998078923f2d62811326d130de991d1a95a
我们有HEAD
→ refs/heads/master
→ 17a02998078923f2d62811326d130de991d1a95a
当 HEAD 被分离时,它直接指向提交 - 而不是通过分支间接指向一个提交。您可以将分离的 HEAD 视为未命名的分支。
git symbolic-ref HEAD
因fatal: ref HEAD is not a symbolic ref
失败fatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
产量17a02998078923f2d62811326d130de991d1a95a
我们有HEAD
→ 17a02998078923f2d62811326d130de991d1a95a
使用分离的 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
这个命令:
master
HEAD
的父提交标识回HEAD
与master
分开的点master
之上播放那些提交最终结果是所有在HEAD
但不是master
中的提交都是master
。 master
仍然检查出来。
关于遥控器:
我在 rebase 中杀死的几个提交被推了出来,而那些在本地提交的新提交不在那里。
无法再使用您的本地历史记录快速转发远程历史记录。您需要强制推送( git push -f
)来覆盖远程历史记录。如果您有任何协作者,通常有必要与他们协调,以便每个人都在同一页面上。
将master
推送到远程origin
,将更新远程跟踪分支origin/master
以指向与master
相同的提交。