如何在rebase分支时保留已合并提交,以便后续cherry-pick到main?
我们采用main、dev、topic分支的常规工作流:有时需向生产环境快速修复,但不能合并dev分支的其他变更,因此会发起PR将topic分支的部分提交(如H、I)合并到dev(无法直接PR到main),之后topic分支还需添加新变更(如J)。
要让topic分支与dev保持同步,不能直接合并dev到topic(否则后续合并topic到main时会带入dev的变更),因此选择rebase操作。但默认rebase会跳过已合并到dev的提交(H、I),导致后续cherry-pick topic分支到main时,仅能拿到未合并的J,丢失H、I的提交记录。
需求是:rebase topic到dev时,保留已合并的提交(转为空提交H'、I'),这样后续cherry-pick整个topic分支到main时,能包含所有提交及其对应变更。
核心解决方案:使用git rebase --keep-empty强制保留空提交
Git默认会自动丢弃rebase过程中产生的空提交,但--keep-empty参数可强制保留这些提交,直接满足需求:
- 切换到目标topic分支:
git checkout topic
- 执行带
--keep-empty的rebase:
git rebase --keep-empty dev
该命令会将topic分支的所有提交(H、I、J)依次在dev的最新提交L上重新应用。由于H、I的变更已通过合并提交K进入dev,重新应用时会生成空提交H'、I',--keep-empty会保留这两个空提交,最终topic分支结构为:L -> H' -> I' -> J。
- (可选)调整提交顺序
如果rebase后提交顺序不符合预期,可通过交互式rebase调整:
git rebase --keep-empty -i HEAD~3
在编辑器中调整提交顺序,确保H'、I'在J前面,保存退出即可。
验证Cherry-Pick效果
当需要将topic分支的所有提交cherry-pick到main分支时,直接执行:
git checkout main git cherry-pick topic~2..topic
(或逐个cherry-pick提交:git cherry-pick <H'-hash> <I'-hash> <J-hash>)
此时,尽管H'、I'是空提交,但Git会检查原提交H、I的变更是否存在于main分支中。由于main分支无这些变更,cherry-pick会重新应用H、I的完整变更,最终main分支将包含H、I、J的所有变更,同时保留完整的提交记录。
场景示例
STARTING STATE dev branch A - B - C - E - F - G \ topic branch H - I - J AFTER PR MERGE dev branch A - B - C - E - F - G - K - L (K is merge commit, contains H and I changes) \ / topic branch H - I - - - - - J NORMAL REBASE dev branch A - B - C - E - F - G - K - L (Only J since H and I are already merged on K) \ topic branch J DESIRED OUTCOME AFTER REBASE (using --keep-empty) dev branch A - B - C - E - F - G - K - L (H' and I' are empty commits) \ topic branch H' - I' - J IN CASE WE WANT TO CHERRY-PICK TOPIC BRANCH INTO MAIN (MERGE ONLY TOPIC CHANGES) dev branch G - K - L (H and I are merged via K) \ topic branch H' - I' - J main branch - - - - - - - - - - - M - N - H - I - J - O
内容的提问来源于stack exchange,提问作者SankE

