我最近遇到了一个我不知道如何处理的git场景。首先,让我们设置场景。
理想的工作流程
假设您正在维护一个大型开源项目的分支,其中上游正在使用拉取请求 (PR( 进行开发。由于上游正在做 PR,他们的 git 历史记录有很多合并提交。
您必须定期将树与上游同步。通常,这是这样的:
git checkout -b sync
git pull upstream master
- 修复合并冲突,在
git add
冲突文件之前,git commit
.
此时,您在树的顶部有一个整洁的小合并提交。嵌套在里面的是上游的所有提交和合并。运行持续集成测试 (CI(,它们通过,分支合并到分支的主分支中。美妙。
有问题的场景
git checkout -b sync
git pull upstream master
- 您可以修复合并冲突,
git add
并git commit
它们。 - 您运行 CI 并且测试失败,因为上游破坏了某些内容。
- 两天后,上游修复了问题。
git pull upstream master
- 再次修复合并冲突。
此时,您的sync
分支包含您创作的两个合并提交。每个单独的合并提交都包含上游的各种提交和合并。
您可以立即运行 CI 并合并,但您不应该这样做,因为您的第一次合并提交会干扰未来的git bisects
。理想情况下,您将有一个合并提交,它是两个合并提交按顺序排列的总和。
如何将这两个合并提交扁平化为一个,同时保留上游的 git 历史记录?
笔记
git rebase --preserve-merges
是 a( 已弃用,b( 全部或全无。您不能有选择地保留上游的所有合并,但会展平您的合并。
我尝试使用git rebase --rebase-merges -i origin/master
并标记第二个合并f
进行修复,但这没有达到预期的效果。我在从未接触过的文件上收到了合并提交。
一种解决方案是从头开始重做整个合并,因为上游是固定的。问题是,即使有rerere
,这也是很多工作。在这些上游同步中,您最终会修复不是合并冲突的内容,而是(例如(编译或逻辑错误。由于这些修复是合并冲突(单独提交(的次要修复程序,因此rerere
不会记录它们的自动解决方案。
如果我理解正确,您需要一个合并提交:上游树,包括最近的修复,与您的sync
分支合并。因此,这就是您应该做的:在原始合并之前将同步分支重置为提交,然后再次执行合并。
如果在原始合并之后但在上游修复可用之前对同步分支进行了其他更改,则可以先将这些提交重定原始合并之前的提交基准:
git checkout -b sync
git rebase --onto ${PREMERGECOMMIT} ${MERGECOMMIT}
git pull upstream master