如何把某一个 commit 合并到当前分支?Git cherry-pick 完整教程
如何把某一个 commit 合并到当前分支?Git cherry-pick 完整教程
在实际开发中,我们经常会遇到这样的情况:另一个分支中有很多提交,但当前分支只需要其中某一个 commit。
这种情况下,没有必要把整个分支
merge进来,直接使用git cherry-pick就可以把指定提交带到当前分支。
一、先说结论:使用 git cherry-pick
假设现在有两个分支:
main:当前稳定分支feature:功能开发分支
feature分支上已经产生了多个 commit,但你只想把其中某一个提交合并到main。
这时先切换到接收提交的目标分支,然后执行:
gitcherry-pick<commit-id>cherry-pick的核心并不是把另一个分支整体合并过来,而是把指定 commit 所引入的改动重新应用到当前分支,并在当前分支上生成一个新的提交。
可以简单记成一句话:
merge 是合分支,cherry-pick 是挑提交。
二、什么情况下应该用 cherry-pick?
git cherry-pick最适合“我只需要这一条提交”的场景。
实际开发中比较常见的情况有:
- 某个 Bug 已经在
dev分支修复,现在需要快速同步到main或release。 - 一个功能分支中有很多 commit,但当前分支只需要其中一个。
- 某个 commit 提交到了错误分支,需要把它带到正确分支。
- 线上完成了一个 Hotfix,需要把同样的修复同步到其他维护分支。
如果你的需求是把整个功能分支一起合并,那么通常应该使用git merge;如果只想拿其中某一个提交,cherry-pick会更加合适。
三、完整操作:把某一个 commit 合并到当前分支
下面直接用一个完整例子说明。
假设需要的 commit 位于feature分支,而最终希望把它放进main分支。
1. 先确认当前分支
首先查看当前仓库有哪些分支:
gitbranch如果当前不在main,先切换到main:
gitswitch main较老版本的 Git 也可以使用:
gitcheckout main这里一定要注意:
git cherry-pick会把指定 commit 的改动应用到当前分支。
所以执行之前一定要先确认自己现在站在哪个分支上,否则很容易把提交放错地方。
2. 检查工作区状态
执行cherry-pick之前,建议先查看当前工作区:
gitstatus如果还有尚未处理的本地修改,最好先提交、暂存或妥善保存,再进行cherry-pick。
这样可以避免当前修改和目标 commit 的改动混在一起,减少冲突和误操作。
3. 找到目标 commit ID
查看提交历史:
gitlog--oneline--all--graph--decorate假设看到:
a72c91f fix: 修复登录状态失效问题 3bd5e84 feat: 新增用户头像上传 1f26a77 refactor: 重构用户服务现在我们只需要第一条修复提交,那么目标 commit ID 就是:
a72c91f一般情况下,Git 显示出来的短 commit ID 就可以直接使用,只要它能够在当前仓库中唯一定位到对应提交。
4. 执行 cherry-pick
确认当前已经处于main分支以后执行:
gitcherry-pick a72c91f如果没有发生冲突,Git 会直接把这个 commit 引入的改动应用到当前分支,并自动创建一个新的提交。
整个标准流程可以看下面这张图:
5. 检查是否成功
查看最近几条提交记录:
gitlog--oneline-5再检查当前工作区:
gitstatus如果提交记录已经出现,并且工作区状态正常,那么这次cherry-pick就完成了。
四、为什么 cherry-pick 以后 commit ID 变了?
很多人第一次使用cherry-pick时会发现一个问题:
明明是同一个提交,为什么进入当前分支之后 commit ID 变了?
这是正常现象。
cherry-pick并不是把原来的 commit 对象原封不动地搬到当前分支,而是把这个 commit 引入的代码改动重新应用一次,然后在当前分支创建新的提交。
新的提交和原提交的父提交关系通常不同,因此生成的新 commit ID 通常也会不同。
所以判断cherry-pick是否成功时,不要只看 commit ID 是否一样,更重要的是检查:
- 目标代码改动是否已经进入当前分支。
- 当前分支是否生成了对应的新提交。
git status是否正常。
五、cherry-pick 发生冲突怎么办?
如果目标 commit 修改的代码,与当前分支中的代码已经产生较大差异,Git 可能无法自动完成合并。
这时cherry-pick会暂停,并提示发生冲突。
先查看当前状态:
gitstatus打开冲突文件,手动处理冲突。
解决完成以后,把处理好的文件加入暂存区:
gitadd.然后继续执行:
gitcherry-pick--continue注意,这时候不要重新执行原来的git cherry-pick <commit-id>。
正确流程是:
发生冲突 ↓ 手动解决冲突 ↓ git add . ↓ git cherry-pick --continue六、不想继续 cherry-pick 了怎么办?
如果执行到一半发现选错 commit,或者冲突过于复杂,希望直接取消这一次操作,可以执行:
gitcherry-pick--abortGit 会尝试把仓库恢复到这次cherry-pick开始之前的状态。
如果正在连续cherry-pick多个提交,并且当前这个提交不想继续应用,可以使用:
gitcherry-pick--skip这几个命令可以这样记:
| 命令 | 作用 |
|---|---|
git cherry-pick --continue | 冲突解决后继续 |
git cherry-pick --abort | 放弃本次 cherry-pick |
git cherry-pick --skip | 跳过当前提交 |
七、cherry-pick 完才发现选错 commit,怎么撤销?
这里需要区分提交是否已经推送到了远程仓库。
情况 1:刚执行完,还没有 push
如果确定刚刚cherry-pick生成的就是最近一个 commit,而且还没有共享给别人,可以退回上一个提交:
gitreset--hardHEAD~1但是要特别注意:
--hard会同时重置提交、暂存区和工作区。
如果工作区还有没有保存的重要内容,可能会直接丢失,因此执行前一定要确认当前修改是否需要保留。
情况 2:已经 push 到远程仓库
如果这个提交已经被推送到公共分支,一般不建议直接使用reset --hard改写共享历史。
先查看提交记录:
gitlog--oneline找到cherry-pick后新生成的 commit ID,然后执行:
gitrevert<new-commit-id>revert会创建一个新的反向提交,用新的 commit 撤销原提交带来的修改,而不是直接把已有历史删除。
这种方式更适合团队协作中的公共分支。
八、一次 cherry-pick 多个 commit
虽然本文重点讲的是“某一个 commit”,但实际开发中也可能需要挑选多个提交。
多个不连续的 commit 可以直接写在命令后面:
gitcherry-pick a72c91f 3bd5e84 1f26a77Git 会按照给出的顺序依次应用这些提交。
如果要选择一段连续的 commit,可以使用提交范围:
gitcherry-pick A^..B这种写法表示把从A到B的这一段提交应用到当前分支,其中包含A和B。
如果中途某一个 commit 发生冲突,整个过程会暂停。解决冲突以后执行:
gitcherry-pick--continueGit 才会继续处理后面的提交。
九、cherry-pick 和 merge 到底有什么区别?
这是最容易混淆的地方。
简单对比一下:
| 对比项 | git merge | git cherry-pick |
|---|---|---|
| 操作对象 | 整个分支 | 指定 commit |
| 是否自动带入其他提交 | 通常会 | 不会自动带入 |
| 提交历史 | 体现分支合并关系 | 在当前分支生成新的提交 |
| 典型场景 | 功能分支整体合并 | 只拿一个修复或小功能 |
| 核心思路 | 合分支 | 挑提交 |
一句话记忆:
merge = 把分支合进来。
cherry-pick = 从提交历史里摘一个 commit 过来。
十、实际开发案例
假设团队现在有两个分支:
main feature/loginfeature/login中产生了三个 commit:
8a11c30 feat: 新增登录页面 91bd722 fix: 修复 token 过期判断 c3a8f05 feat: 新增第三方登录现在main分支只急需token修复,并不想把登录页面和第三方登录功能一起带进去。
先切换到main:
gitswitch main检查工作区:
gitstatus然后只选择修复提交:
gitcherry-pick 91bd722最后查看提交历史:
gitlog--oneline-5这样main只会得到91bd722所引入的代码改动,而另外两个功能 commit 不会因为这次操作自动进入main。
这就是cherry-pick最典型的使用场景。
十一、最容易踩的几个坑
1. 当前分支切错了
这是最常见的问题。
记住:
谁要接收这个 commit,就先切换到谁。
例如需要把某个提交合到main:
gitswitch main然后再执行cherry-pick。
2. 工作区还有未提交修改
执行前先检查:
gitstatus不要让正在开发但还没处理的代码与cherry-pick的改动混在一起。
3. 冲突以后又重新执行 cherry-pick
错误思路:冲突以后再次执行:
gitcherry-pick<commit-id>正确做法是解决冲突后:
gitadd.gitcherry-pick--continue4. 看到 commit ID 不一样就认为失败了
cherry-pick后通常会生成新的 commit,因此 commit ID 变化并不代表失败。
重点检查代码改动和提交记录是否正确。
5. 已经 push 以后随便 reset --hard
如果已经推送到公共分支,直接改写提交历史可能影响其他协作者。
这种情况下通常更适合:
gitrevert<commit-id>6. 整个功能都需要,却一个一个 cherry-pick
如果你最终就是需要整个功能分支,那么通常直接merge更合理。
如果几十个 commit 全靠cherry-pick一个个挑,提交历史反而容易变得难以理解和维护。
十二、常用命令速查
查看当前状态
gitstatus查看提交历史
gitlog--oneline--all--graph--decorate切换目标分支
gitswitch main挑选一个 commit
gitcherry-pick<commit-id>冲突解决后继续
gitcherry-pick--continue放弃本次操作
gitcherry-pick--abort跳过当前提交
gitcherry-pick--skip撤销已经共享出去的提交
gitrevert<new-commit-id>十三、总结
如果你的需求是:
只把另一个分支中的某一个 commit 合并到当前分支。
最直接的方案就是:
gitswitch<target-branch>gitcherry-pick<commit-id>实际操作时可以记住下面四步:
- 先切到接收提交的目标分支。
- 找到需要的 commit ID。
- 执行
git cherry-pick <commit-id>。 - 使用
git log和git status检查结果。
最重要的一点是:
cherry-pick 操作的是 commit,不是整个分支。
只要把这一点理解清楚,什么时候应该用merge,什么时候应该用cherry-pick,基本就不会搞混了。
参考资料
- Git 官方文档:
git-cherry-pick Documentation - Git 官方文档地址:https://git-scm.com/docs/git-cherry-pick