我是 Git 分支复杂性的新手。我总是在一个分支上工作并提交更改,然后定期推送到我的远程源。
最近的某个地方,我重置了一些文件以使它们退出提交暂存,后来又做了一个 rebase -i
摆脱最近的几个本地提交。现在我处于一种我不太明白的状态。
在我的工作区,git log
显示了我所期望的——我在正确的火车上,有我不想消失的提交,还有新的提交,等等。
但是我只是推送到远程存储库,有什么不同 - 我在 rebase 中杀死的一些提交被推送了,而本地提交的新提交不在那里。
我认为“master/origin”与 HEAD 是分离的,但我不是 100% 清楚这意味着什么,如何使用命令行工具对其进行可视化,以及如何修复它。
最佳答案
首先澄清一下what HEAD is以及分离时的含义。
HEAD 是当前 check out 提交的符号名称。当 HEAD 没有分离时(“正常”1 情况:你有一个分支被 check out ),HEAD 实际上指向一个分支的“ref”,而分支指向提交。 HEAD 因此“附加”到一个分支。当您进行新提交时, HEAD 指向的分支将更新为指向新提交。 HEAD 会自动跟随,因为它只是指向分支。
git symbolic-ref HEAD
yield refs/heads/master
名为“master”的分支被 check out 。 git rev-parse refs/heads/master
产量17a02998078923f2d62811326d130de991d1a95a
该提交是主分支的当前提示或“头”。 git rev-parse HEAD
也产生 17a02998078923f2d62811326d130de991d1a95a
这就是“符号引用”的含义。它通过其他一些引用指向一个对象。(符号引用最初是作为符号链接(symbolic link)实现的,但后来改为带有额外解释的纯文件,以便它们可以在没有符号链接(symbolic link)的平台上使用。)
我们有
HEAD
→ refs/heads/master
→ 17a02998078923f2d62811326d130de991d1a95a
当 HEAD 被分离时,它直接指向一个提交——而不是通过一个分支间接指向一个提交。您可以将分离的 HEAD 视为位于未命名分支上。
git symbolic-ref HEAD
失败 fatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
yield 17a02998078923f2d62811326d130de991d1a95a
由于它不是符号引用,因此它必须直接指向提交本身。 我们有
HEAD
→ 17a02998078923f2d62811326d130de991d1a95a
使用分离的 HEAD 需要记住的重要一点是,如果它指向的提交没有被引用(没有其他 ref 可以访问它),那么当您 check out 其他提交时,它将成为“悬空”。最终,这些悬空提交将通过垃圾收集过程进行修剪(默认情况下,它们至少保留 2 周,并且可以通过 HEAD 的 reflog 引用保留更长时间)。
1
用一个独立的 HEAD 做“正常”的工作是完全没问题的,你只需要跟踪你正在做的事情,以避免不得不从 reflog 中获取丢弃的历史记录。
交互式 rebase 的中间步骤是通过分离的 HEAD 完成的(部分是为了避免污染事件分支的 reflog)。如果您完成完整的 rebase 操作,它将使用 rebase 操作的累积结果更新您的原始分支,并将 HEAD 重新附加到原始分支。我的猜测是你从未完全完成 rebase 过程;这将为您留下一个分离的 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/
来检查 rebase 是否正在处理中。 .您可以通过删除该目录来手动清理正在进行的 rebase (例如,如果您不再记得事件 rebase 操作的目的和上下文)。通常你会使用 git rebase --abort
,但这会进行一些您可能想要避免的额外重置(它将 HEAD 移回原始分支并将其重置回原始提交,这将撤消我们上面所做的一些工作)。
关于git - 如何协调分离的 HEAD 与 master/origin?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5772192/