在git-rebase手册中有一个名为“从上游rebase恢复”的章节,对此进行了很好的描述。
获取
对于您的特定情况,让我们来看看会发生什么。如果您只是获取(fetch),那么它只是更新您的远程跟踪分支。这仍然可以正常工作 - 但它会给您一个警告:
From <url>:
+ abc123...def456 master -> origin/master (forced update)
拉取
无论是普通的合并(merging)还是变基(rebasing),都会在内部调用fetch。因此,如果您还没有进行过获取操作,则会看到“强制更新”警告。如果您已经获取了,之前就会出现强制更新警告,并且现在没有强制更新需要警告。如果在合并后有大量的差异报告,您也可能会错过强制更新警告。在获取后,git pull 就会按照所请求的方式调用合并或变基操作。这时就会变得非常危险。就 Git 而言,提交 C
和 D
现在只是本地提交。它不会关心这些提交曾经被发布过。因此,Git 会像平常一样进行合并/变基。
合并:
- A - B - L - M - N - O (origin/master)
\ \
C - D - X - Y - Z - Q (master)
变基(Rebase):
- A - B - L - M - N - O (origin/master) - C' - D' - X' - Y' - Z' (master)
现在,如果删除提交C和D会使后续提交不同,那么就可能会遇到冲突。
合并冲突是你唯一会注意到的其他错误。但是如果它们是孤立的更改,那么一切都会“很好”。如果用户没有注意到这一点,那么他们可能随后推送此历史记录,从而重新引入已删除的提交!有时这可能相对温和。也许L实际上是在提交消息中修正了拼写错误的C,而MNO与DEF相同,只是父级不同。因此,重新引入C和D将不会产生任何更多的影响,只会使历史记录杂乱无章。但是,也可能非常危险:也许删除C修复了某些可怕的错误,并且已经被重新引入。
避免问题
这就是为什么重写已发布历史记录是一个非常糟糕的想法。最好的情况是最终得到一些重复提交,最坏的情况是用户不知情地破坏了一切。因此,如果确实发生了这种情况,第一件事就是告诉每个人并指导他们如何恢复。下一步是警惕地监视随后发布的所有内容,以确保不会重新引入旧提交。如果您在公共存储库中获取数据,则希望您足够信任维护人员永远不会重写稳定分支,或者会告诉您他们这样做了。如果您不信任他们,那么最好的做法是先获取然后合并/变基,而不是拉取,以便您可以注意到“强制更新”消息并非常谨慎地进行操作。
本地恢复
如何恢复的详细信息因情况而异;我建议查阅前面提到的手册页。很难确定您需要做什么 - 这取决于C是否被重写为L(也许D被重写为M),或者它们是全新的提交,以及您想要变基还是合并。如果您只想变基,那么将XYZ变基到O就足够了。如果您想要合并,您需要将XYZ变基到B或M,然后合并O。