同事是git的新手。他从事某个功能分支已经有一段时间了,现在已经创建了一个PR(如果重要的话,请使用Azure DevOps)。
[不幸的是,他不知道git rebase
,因此他一直使用git pull origin master
进行同步,这导致了很多合并提交。 (在他的功能分支上有20个“实际”提交和9个合并提交)
现在,这很好,但是结果是PR的差异视图不仅显示了他的更改,而且还显示了同时在master上应用的所有其他更改。现在基本上不可能进行适当的代码审查,因为他的更改与所有其他更改都没有区别。
现在,我的计划是以某种方式重放他的所有更改,但是每当他进行合并时,我都会进行重新设置基准。每当在重新设置基准期间发生冲突时,在相应的合并提交的更改中进行混合就可以完美地解决该问题(理论上)。大多数合并都非常困难,因此无法手动重做,因为这项工作已经完成。
实现此目标的最佳方法是什么?
我尝试过git rebase master
,但这不包括合并提交,因此必须手动完成。
我也尝试过git rebase --preserve-merges master
,但是由于某些原因,这只会做基础直到最新的合并提交为止(见下文)。
[如果没有更好的选择,我将不得不做20 + 9个樱桃小菜...
交谈中的图片,情况是这样:
A---B---C- ... --D---E---F master
\ \ ... \
G---m---H- ... --m---I---J feature
我想要这个:
A---B---C- ... --D---E---F master
\
G'--m'--H' ... --m'--I'--J' feature
选项1.只会给我这个,但我想获得m
(不一定是提交,但我希望以某种方式解决那些冲突):
A---B---C- ... --D---E---F master
\
G'------H' ... ------I'--J' feature
选项2.只会给我这个,没有太大帮助:
A---B---C- ... --D---E---F master
\ \ ... \ \
G---m---H- ... --m-------m'--I'--J' feature
Rebase无法做到这一点。它要么完全删除合并,要么re-performs合并。如果它重新执行合并,则您获得的合并提交就是实际的合并提交。在您的情况下,您需要使用-m
进行等同的选择。 (我认为您想要-m 1
,但请确保使用,尤其是在使用以下内容之前。)
[如果没有更好的选择,我将不得不做20 + 9个樱桃小菜...
这就是要走的路。使用git rev-list
或类似的名称列出要复制的所有提交。记下其中哪些是合并。然后写一个小脚本:
git cherry-pick <hash-of-G>
git cherry-pick -m 1 <hash-of-merge#1> # or maybe -m 2?
git cherry-pick <hash-of-H>
依此类推。一次运行一个命令,以使您知道在哪里以及何时发生故障,或者您对错误的处理有足够的把握,将其作为设置为-e
的脚本运行,以免出现故障。其余的内容。
我找到了一个非常顺利的解决方案:
让您完全处于开始进行功能时的状态
git checkout -b replay_feature <hash-of-A>
完全重做他的操作,直到完成合并:
git cherry-pick <hash-of-G> # redo his non-merge commit(s)
现在,他做了git merge master
,所以我改了git rebase master
:
git rebase <hash-of-B> # back then, B was HEAD of master
现在,我正在重新进行基础设置,面临与他所面临的完全相同的冲突,他用m
解决了该冲突。因此,为了以与他完全相同的方式解决该问题,我只是从他的合并提交中签出所有冲突的文件。
git checkout <hash-of-merge> -- file-in-conflict.cpp # do this for all conflicts
# make sure everything compiles
git add .
git rebase --continue
重复第3步,直到完成变基
重复步骤2至5.,直到重播他的全部作品,将所有合并替换为变基并应用他的冲突解决方案。最后,比较分支replay_feature
和feature
。如果一切顺利,则所有文件应相同。
git diff replay_feature feature # should not show anything