Git + Gerrit 第九课:cherry-pick 挑选提交

本节目标

这一节学习 Git 中非常实用的命令:cherry-pick

你要理解这些问题:

复制代码
什么是 cherry-pick?
什么时候需要 cherry-pick?
cherry-pick 和 merge 有什么区别?
如何把某个提交复制到另一个分支?
cherry-pick 冲突怎么解决?
Gerrit 中如何挑选修复提交到 release 分支?

本节重点命令:

复制代码
git log --oneline
git switch
git cherry-pick
git cherry-pick --continue
git cherry-pick --abort
git cherry-pick --skip
git status

1. cherry-pick 是什么

cherry-pick 的意思是:

复制代码
从一串提交中,挑选某一个提交,复制到当前分支。

假设有两个分支:

复制代码
A --- B --- C --- D    main
     \
      E --- F          release

现在你发现 main 分支上的 D 是一个重要 bug 修复。

你不想把整个 main 都合并到 release,只想把 D 这个提交拿过来。

这时可以在 release 分支执行:

复制代码
git cherry-pick D

结果:

复制代码
A --- B --- C --- D        main
     \
      E --- F --- D'       release

注意:

复制代码
D' 是 D 的复制版本。
它的代码改动和 D 类似,但 commit id 不一样。

2. cherry-pick 的直观理解

可以这样理解:

复制代码
merge 是把一个分支整体合进来。
cherry-pick 是只挑某一个提交拿过来。

例如:

复制代码
main 分支有 10 个新提交。
release 分支只需要其中 1 个 bug 修复提交。

这时不适合直接 merge main

因为 merge 会带来很多不需要的修改。

更合适的是:

复制代码
git cherry-pick 修复提交ID

3. cherry-pick 和 merge 的区别

对比项 merge cherry-pick
操作对象 一个分支 一个或多个提交
结果 合并整个分支历史 复制指定提交
是否带入其他提交 通常会 不会,只拿指定提交
常见用途 整合功能分支 把修复挑到其他分支
commit id 保留原历史关系 生成新的 commit id

一句话:

复制代码
merge 是合并分支,cherry-pick 是复制提交。

4. 什么时候使用 cherry-pick

常见场景:

  • master/main 上的 bug 修复复制到 release 分支

  • release 上的紧急修复复制回 develop

  • 从别人分支挑一个有用提交到自己分支

  • 只想要某个提交,不想合并整个分支

  • 多版本维护时,把同一个修复同步到多个版本分支

典型公司场景:

复制代码
产品已经发布 v1.0,对应 release/v1.0 分支。
开发主线 main 已经继续开发 v2.0。
现在 main 上修了一个严重 bug。
这个 bug 也影响 v1.0。
你需要把这个 bug 修复提交 cherry-pick 到 release/v1.0。

5. 什么时候不适合 cherry-pick

不适合场景:

  • 你其实需要整个功能分支

  • 提交之间依赖很强,只挑一个会编译失败

  • 想保持完整分支历史

  • 不确定这个提交是否依赖前面的提交

  • 大量提交都要同步,这时 merge 或 rebase 可能更合适

使用前要思考:

复制代码
这个提交能不能单独工作?
它有没有依赖其他提交?
挑过来会不会缺文件、缺接口、缺配置?

6. cherry-pick 基本流程

假设你要把 main 上的某个提交挑到 release/v1.0

第一步,找到提交 ID:

复制代码
git log --oneline

示例:

复制代码
def5678 修复登录空指针问题
abc1234 实现用户登录功能

第二步,切到目标分支:

复制代码
git switch release/v1.0

第三步,执行 cherry-pick:

复制代码
git cherry-pick def5678

第四步,检查历史:

复制代码
git log --oneline

你会看到当前分支多了一个新提交。

7. cherry-pick 会生成新的 commit id

假设原提交是:

复制代码
def5678 修复登录空指针问题

你在 release/v1.0 上执行:

复制代码
git cherry-pick def5678

新提交可能变成:

复制代码
9999999 修复登录空指针问题

标题一样,代码改动类似,但 commit id 不一样。

原因是:

复制代码
新提交的父提交不同,所以 commit id 一定不同。

这很正常。

8. cherry-pick 多个提交

你可以一次挑多个提交:

复制代码
git cherry-pick abc1234 def5678

Git 会按顺序应用这些提交。

也可以挑一个连续范围。

例如:

复制代码
git cherry-pick A^..C

意思是:

复制代码
从 A 到 C,包括 A 和 C。

新手阶段建议先一个一个挑:

复制代码
git cherry-pick 提交ID

这样更容易定位问题。

9. cherry-pick 不自动提交

默认情况下:

复制代码
git cherry-pick 提交ID

会应用修改并自动创建提交。

如果你想只应用修改,不自动提交,可以使用:

复制代码
git cherry-pick -n 提交ID

或者:

复制代码
git cherry-pick --no-commit 提交ID

作用是:

复制代码
把指定提交的修改放到当前工作区和暂存区,但不自动 commit。

适合场景:

复制代码
你想挑多个提交后合成一个提交。
你想先检查或调整代码再提交。

10. cherry-pick 可能冲突

如果目标分支和原提交改到了同一个位置,就可能冲突。

例如:

复制代码
git cherry-pick def5678

可能看到:

复制代码
CONFLICT (content): Merge conflict in config.txt
error: could not apply def5678... 修复登录空指针问题

意思是:

复制代码
Git 在复制这个提交时遇到了冲突。
你需要手动解决。

11. cherry-pick 冲突解决流程

冲突后先看状态:

复制代码
git status

打开冲突文件,处理冲突标记:

复制代码
<<<<<<< HEAD
当前分支内容
=======
被 cherry-pick 的提交内容
>>>>>>> def5678

整理成最终正确内容后:

复制代码
git add 冲突文件
git cherry-pick --continue

注意:

复制代码
cherry-pick 冲突解决后,用 git cherry-pick --continue。
不是直接 git commit。

12. 放弃 cherry-pick

如果你发现挑错了提交,或者冲突太复杂,可以放弃:

复制代码
git cherry-pick --abort

作用是:

复制代码
取消当前 cherry-pick,回到 cherry-pick 前的状态。

这和前面学过的:

复制代码
git merge --abort
git rebase --abort
git revert --abort

思想类似。

13. 跳过当前提交

如果一次 cherry-pick 多个提交,中途某个提交不想要了,可以:

复制代码
git cherry-pick --skip

作用是:

复制代码
跳过当前这个提交,继续后面的提交。

新手不要随便使用 --skip

因为它可能导致:

复制代码
后面的提交缺少依赖。
最终代码不完整。

14. Gerrit 中的 cherry-pick 场景

Gerrit 中常见场景:

复制代码
一个 bug 修复已经合入 master。
现在 release 分支也需要这个修复。

流程通常是:

复制代码
git fetch origin
git switch release/v1.0
git cherry-pick 修复提交ID
git push origin HEAD:refs/for/release/v1.0

这样 Gerrit 会在 release/v1.0 目标分支上创建一个新的 Change。

注意:

复制代码
这通常是一个新的 Change。
因为目标分支不同,commit id 也不同。

15. Gerrit 中 Change-Id 的注意点

如果 cherry-pick 的提交来自 Gerrit,它的 commit message 里可能已经有:

复制代码
Change-Id: Iabc1234567890abcdef1234567890abcdef1234

当你 cherry-pick 到另一个目标分支时,很多 Gerrit 项目允许同一个 Change-Id 出现在不同目标分支上。

但不同公司规范可能不同。

有些团队希望:

复制代码
同一个修复在不同分支上保留同一个 Change-Id,方便追踪。

也有团队希望:

复制代码
不同目标分支生成不同 Change。

实际工作中要遵守项目规范。

新手先记住:

复制代码
不要随便删除或修改 Change-Id。
如果 Gerrit 提示 Change-Id 问题,再按团队规范处理。

16. cherry-pick 后如何检查

执行 cherry-pick 后,不要马上推送。

建议检查:

复制代码
git status
git log --oneline -5
git show --stat HEAD

如果想看最新提交具体内容:

复制代码
git show HEAD

重点确认:

复制代码
是不是挑了正确的提交?
有没有引入不该有的文件?
代码是否能在当前分支独立工作?
提交信息是否符合规范?
Change-Id 是否符合 Gerrit 要求?

17. cherry-pick 和 amend 的配合

有时 cherry-pick 后,你需要稍微调整代码才能适配目标分支。

例如:

复制代码
master 上方法叫 ValidateUser
release 分支旧代码里方法叫 CheckUser

你 cherry-pick 后修改适配代码。

然后可以:

复制代码
git add .
git commit --amend --no-edit

这样最终还是一个清晰的提交。

再推送到 Gerrit:

复制代码
git push origin HEAD:refs/for/release/v1.0

18. 实战练习一:基础 cherry-pick

创建练习仓库:

复制代码
mkdir git-cherry-pick-demo
cd git-cherry-pick-demo
git init

创建基础提交:

复制代码
echo "base" > readme.txt
git add readme.txt
git commit -m "添加基础文件"

创建 release 分支:

复制代码
git switch -c release/v1.0
echo "release version" >> readme.txt
git add readme.txt
git commit -m "添加 release 版本说明"

切回主分支:

复制代码
git switch main

如果主分支叫 master

复制代码
git switch master

在主分支创建 bug 修复提交:

复制代码
echo "bug fix" > fix.txt
git add fix.txt
git commit -m "修复示例 bug"

查看提交 ID:

复制代码
git log --oneline

假设最新提交是:

复制代码
def5678 修复示例 bug

切到 release 分支:

复制代码
git switch release/v1.0

挑选这个提交:

复制代码
git cherry-pick def5678

查看历史:

复制代码
git log --oneline --graph --all

19. 实战练习二:cherry-pick 冲突

创建练习仓库:

复制代码
mkdir git-cherry-pick-conflict-demo
cd git-cherry-pick-conflict-demo
git init

创建基础文件:

复制代码
echo "version: base" > config.txt
git add config.txt
git commit -m "添加基础配置"

创建 release 分支:

复制代码
git switch -c release/v1.0
echo "version: release" > config.txt
git add config.txt
git commit -m "修改 release 配置"

切回主分支:

复制代码
git switch main

如果主分支叫 master

复制代码
git switch master

主分支也修改同一行:

复制代码
echo "version: main fix" > config.txt
git add config.txt
git commit -m "修复主分支配置"

记录最新提交 ID:

复制代码
git log --oneline

切回 release:

复制代码
git switch release/v1.0

执行 cherry-pick:

复制代码
git cherry-pick 提交ID

这时应该会出现冲突。

20. 实战练习三:解决 cherry-pick 冲突

查看状态:

复制代码
git status

打开 config.txt,你可能看到:

复制代码
<<<<<<< HEAD
version: release
=======
version: main fix
>>>>>>> 修复主分支配置

改成最终内容:

复制代码
version: release with main fix

然后:

复制代码
git add config.txt
git cherry-pick --continue

查看历史:

复制代码
git log --oneline --graph --all

21. 实战练习四:不自动提交

假设你只想应用某个提交的修改,但暂时不提交:

复制代码
git cherry-pick -n 提交ID

查看状态:

复制代码
git status
git diff --cached

你可以继续调整代码。

调整完成后再提交:

复制代码
git add .
git commit -m "挑选并适配某个修复"

22. 常见错误

错误一:挑错分支

执行 cherry-pick 前先确认当前分支:

复制代码
git branch
git status

你必须在目标分支上执行 cherry-pick

错误二:不检查提交依赖

有些提交依赖前面的提交。

只挑一个可能导致:

复制代码
编译失败
方法不存在
配置缺失
测试失败

挑选前要看:

复制代码
git show 提交ID

错误三:冲突后直接 git commit

cherry-pick 冲突解决后应该:

复制代码
git cherry-pick --continue

不是直接:

复制代码
git commit

错误四:以为 commit id 会一样

cherry-pick 后 commit id 通常会变化。

这是正常的。

错误五:随便修改 Change-Id

Gerrit 项目中不要随便删改 Change-Id

如果推送失败或生成了不符合预期的 Change,先确认团队规范。

23. 本节必须记住的命令

复制代码
git cherry-pick 提交ID
git cherry-pick -n 提交ID
git cherry-pick --continue
git cherry-pick --abort
git cherry-pick --skip
git show 提交ID
git log --oneline

对应含义:

复制代码
git cherry-pick 提交ID          把指定提交复制到当前分支
git cherry-pick -n 提交ID       只应用修改,不自动提交
git cherry-pick --continue      解决冲突后继续
git cherry-pick --abort         放弃当前 cherry-pick
git cherry-pick --skip          跳过当前提交
git show 提交ID                 查看某个提交内容
git log --oneline               查看提交历史

24. 本节总结

这一节你学习了 cherry-pick

  • cherry-pick 用来把某个提交复制到当前分支

  • 它适合把 bug 修复同步到 release 分支

  • 它和 merge 不同,merge 是合并分支,cherry-pick 是挑选提交

  • cherry-pick 后通常会生成新的 commit id

  • cherry-pick 可能产生冲突

  • 冲突解决后要用 git cherry-pick --continue

  • Gerrit 中常用 cherry-pick 把修复提交推到不同目标分支评审

最重要的一句话:

复制代码
cherry-pick 是复制一个提交,不是合并整个分支。

下一节建议学习:

复制代码
Git tag 与 release:如何给版本打标签,以及发布版本在 Git/Gerrit 中如何管理。
相关推荐
之歆3 小时前
Day04_Git完全指南:从入门到精通的版本控制精通
git
码出财富3 小时前
InsForge 后端分支管理实战指南
git
2601_961194024 小时前
2026六级词汇PDF下载|大学英语六级单词表+音频PDF
windows·git·eclipse·pdf·github
幽冥三王爷5 小时前
Git 操作常见问题与处理办法
git
独挽离人7 小时前
git标准推送流程
git
无人生还别怕7 小时前
搭建gitlab服务并接入openldap认证
git·gitlab·github·openldap·ldap·统一认证
努力努力再努力wz9 小时前
【Qt入门系列】一文掌握 Qt 常用显示类控件:QLCDNumber、QProgressBar 与 QCalendarWidget
c语言·开发语言·数据结构·数据库·c++·git·qt
查拉图斯特拉面条9 小时前
Git操作指南:克隆、提交、推送与避坑大全
大数据·git·elasticsearch
恋喵大鲤鱼11 小时前
git status
git·git status