我是 Git 分支复杂性的新手。我总是在一个分支上工作并提交更改,然后定期推送到我的远程源。
最近的某个地方,我对一些文件进行了重置以使它们脱离提交暂存状态,后来又做了一个rebase -i以摆脱最近的几个本地提交。现在我处于一种我不太了解的状态。
rebase -i
在我的工作区域中,git log完全显示了我的期望——我在正确的火车上,有我不想消失的提交,还有新的提交,等等。
git log
但是我只是推送到远程存储库,有什么不同 - 我在 rebase 中杀死的几个提交被推送了,而本地提交的新提交不存在。
我认为“master/origin”与 HEAD 是分离的,但我不是 100% 清楚这意味着什么,如何使用命令行工具对其进行可视化,以及如何修复它。
HEAD 是当前签出提交的符号名称。当 HEAD 未分离时(“正常” 1情况:您已签出一个分支),HEAD 实际上指向一个分支的“ref”,而该分支指向提交。HEAD 因此被“附加”到一个分支上。当您进行新的提交时,HEAD 指向的分支会更新为指向新的提交。HEAD 自动跟随,因为它只是指向分支。
git symbolic-ref HEAD
refs/heads/master
git rev-parse refs/heads/master
17a02998078923f2d62811326d130de991d1a95a
git rev-parse HEAD
我们有HEAD→ refs/heads/master→17a02998078923f2d62811326d130de991d1a95a
HEAD
当 HEAD 分离时,它直接指向一个提交,而不是通过分支间接指向一个提交。您可以将分离的 HEAD 视为位于未命名的分支上。
fatal: ref HEAD is not a symbolic ref
我们有HEAD→17a02998078923f2d62811326d130de991d1a95a
使用分离的 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)
git checkout -b temp
这会将您的 HEAD 重新附加到新temp分支。
temp
接下来,您应该将当前提交(及其历史记录)与您期望工作的正常分支进行比较:
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp git diff master temp git diff origin/master temp
(您可能想要尝试使用日志选项:添加-p、离开--pretty=…以查看整个日志消息等)
-p
--pretty=…
如果您的新temp分支看起来不错,您可能需要更新(例如)master以指向它:
master
git branch -f master temp git checkout master
(这两个命令可以简写为git checkout -B master temp)
git checkout -B master temp
然后您可以删除临时分支:
git branch -d temp
最后,您可能想要推送重新建立的历史记录:
git push origin master
--force如果远程分支无法“快速转发”到新提交(即您删除,或重写了一些现有提交,或以其他方式重写了一些历史记录),您可能需要添加到此命令的末尾以进行推送。
--force
如果您正在进行 rebase 操作,您可能应该清理它。您可以通过查找目录来检查变基是否正在进行中.git/rebase-merge/。您可以通过删除该目录来手动清理正在进行的变基(例如,如果您不再记得活动变基操作的目的和上下文)。通常您会使用git rebase --abort,但这会进行一些您可能希望避免的额外重置(它将 HEAD 移回原始分支并将其重置回原始提交,这将撤消我们在上面所做的一些工作)。
.git/rebase-merge/
git rebase --abort