需要把一个分支上的几次提交移植到当前分支时,最直接的做法是逐个执行:
git cherry-pick abc123
git cherry-pick b81e4d6
git cherry-pick d4e8b73
如果这些提交在历史上是连续的,可以使用一个范围一次完成:
git cherry-pick abc123^..d4e8b73
这会按提交顺序应用从 abc123 到 d4e8b73 的所有提交,并在当前分支上为每个提交创建一个新的提交。
为什么是 abc123^..d4e8b73?
Git 的双点范围是“左边不包含,右边包含”:
abc123..d4e8b73
表示包含 d4e8b73 及其历史,但排除 abc123 及其祖先。因此它不会包含起点 abc123。
abc123^ 表示 abc123 的父提交。把它放在左边以后:
abc123^..d4e8b73
就会排除 abc123 的父提交及更早历史,同时包含 abc123 本身,最终得到一个两端都包含的范围:
abc123, 之后的提交, ..., d4e8b73
这里的 ^ 不是 Cherry-pick 专用语法,而是 Git revision 中用于表示父提交的写法。
执行前先确认范围
范围写错时,Cherry-pick 可能会应用多余的提交。执行前可以先查看 Git 将要处理的提交:
git log --oneline --reverse abc123^..d4e8b73
--reverse 会让提交按照从旧到新的顺序显示,便于检查起点和终点是否正确。
如果想同时查看分支关系,可以使用:
git log --graph --oneline abc123^..d4e8b73
确认无误后,切换到接收提交的目标分支:
git switch release
git status
git cherry-pick abc123^..d4e8b73
执行前最好保证工作区干净。Cherry-pick 会把每个提交的改动重新应用到当前 HEAD,所以它不是把原提交直接搬过来,而是在目标分支上生成新的提交。
不包含起点提交
如果只想应用 abc123 之后的提交,不包含 abc123,直接使用普通的双点范围:
git cherry-pick abc123..d4e8b73
可以简单记成:
A..B 不包含 A,包含 B
A^..B 包含 A,也包含 B
只挑选不连续的提交
提交不连续时,可以直接在同一条命令中列出多个提交:
git cherry-pick 7f3a9c2 b81e4d6 d4e8b73
Git 会按照命令中从左到右的顺序应用它们。这适合只移植几个独立修复,也可以用来明确调整应用顺序。不过,如果后一个提交依赖前一个提交,最好保持原本的依赖顺序,否则更容易产生冲突。
想合并成一个提交
默认情况下,范围中的每个提交都会在目标分支上生成一个新提交。如果只想把整段改动合并成一个提交,可以加上 --no-commit:
git cherry-pick --no-commit abc123^..d4e8b73
git commit -m "Backport selected changes"
--no-commit 会应用改动,但不会自动提交。确认工作区内容后,再手动创建一个提交即可。
发生冲突时怎么办?
范围 Cherry-pick 本质上是按顺序处理多个提交,其中某一个提交发生冲突时,Git 会暂停在这个提交上。解决冲突并加入暂存区后,继续执行:
git add <冲突文件>
git cherry-pick --continue
如果当前提交不需要,可以跳过它:
git cherry-pick --skip
如果想取消整个这次范围操作,回到开始前的状态:
git cherry-pick --abort
一个容易忽略的边界
A^..B 表示的是 Git 提交图上的可达范围,不一定等于界面上看到的“从 A 到 B 的一条直线”。如果历史中有分支合并,范围可能包含额外的提交。执行前用 git log --graph 检查,通常比凭记忆输入 SHA 更可靠。
如果范围中包含合并提交,Git 通常需要知道要以哪个父提交为主线:
git cherry-pick -m 1 <merge-commit>
普通的线性提交不需要 -m。合并提交的选择取决于具体历史,不应该随意套用同一个父编号。
总结
移植一段连续提交时,最常用的写法是:
git cherry-pick A^..B
记住三件事就够了:
A..B不包含A。A^..B把A也包含进来。- 执行前先用
git log --oneline --reverse A^..B确认范围。
参考:Cherry-picking a range of commits in git、git-cherry-pick 官方文档、Git revisions 官方文档。