cherry-pick是重放变更并生成新提交,哈希值必然不同、历史分叉;多提交按参数顺序逐个应用,范围a..b不含a,需写a^..b;冲突时须git add后git cherry-pick --continue,不可直接commit。

cherry-pick 不是“复制粘贴提交”,而是重放变更并生成新提交——这意味着历史会分叉,哈希值必然不同,直接回退或 revert 原提交不会影响 cherry-pick 出来的那个。
cherry-pick 多提交时的顺序和范围陷阱
很多人以为 git cherry-pick A B C 就是“按字母顺序”应用,其实 Git 严格按你列出的**参数顺序**逐个重放:先 A,再 B,最后 C。如果 B 依赖 A 的变更(比如 A 新增了函数,B 调用了它),而你漏掉 A 或顺序写反,就会报错 error: could not apply B...: failed to merge。
用范围语法更要小心:A..B 表示 “从 A 的父提交开始,到 B(含)为止的所有提交”,但**不包含 A 本身**;想包含 A,得写 A^..B 或 A~1..B。更稳妥的做法是先用 git log --oneline A^..B 预览实际会挑哪些提交,再执行。
- 连续提交推荐用
git cherry-pick A^..B,比手动列一串 hash 更可靠 - 非连续提交必须显式列出,且确保彼此无隐式依赖
- 如果中途失败,
CHERRY_PICK_HEAD会指向卡住的那个提交,可用git status查看
解决 cherry-pick 冲突时别跳过 --continue
冲突不是错误,而是 Git 在说:“这部分变更没法自动套用,请你决定怎么合并”。常见误区是手动改完文件后直接 git commit ——这会创建一个普通提交,破坏 cherry-pick 流程,后续 --continue 会报错 fatal: You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)。
正确流程只有三步:改冲突 → git add <file></file> → git cherry-pick --continue。跳过中间任意一步,都可能导致状态卡死。
- 想放弃当前 cherry-pick?用
git cherry-pick --abort,它会干净回退到操作前状态 - 想跳过当前这个有冲突的提交?用
git cherry-pick --skip,但要确认跳过不影响逻辑 - 冲突文件里的
和 <code>>>>>>> commit-hash标记必须全部删掉,否则提交会把标记当代码
cherry-pick 合并提交必须加 -m 参数
对普通提交,git cherry-pick abc123 能直接运行;但对合并提交(比如 git merge feature 产生的那个提交),默认会报错 fatal: commit abc123 is a merge but no -m option was provided。因为 Git 不知道该以哪边为“主线”来计算差异。
此时必须指定 -m 1 或 -m 2:-m 1 表示“以第一个父提交为基准”(通常是被合并进来的分支的上一个提交),-m 2 表示“以第二个父提交为基准”(通常是当前分支合并前的 HEAD)。多数情况下你要的是 -m 1,即还原“feature 分支带来的变更”。
- 查合并提交的父提交:用
git show --pretty=%P -s abc123,输出两个哈希,前者是-m 1,后者是-m 2 - 加
-x选项时,Git 会自动在提交信息末尾加(cherry picked from commit abc123),方便追溯来源 - 加
-n可暂存变更不提交,适合 cherry-pick 后还要微调或合入其他改动
最常被忽略的一点:cherry-pick 出来的提交,作者(author)是原提交作者,但提交者(committer)是你自己。如果团队审计要求提交者与作者一致,得配 git config --global user.name 和 user.email 与原作者完全匹配——但这通常不推荐,容易混淆责任归属。











