12、Git高级合并:git cherry-pick、git rebase vs git merge 的抉择、rebase黄金法则
合并,是团队协作里最常碰到的操作。但很多人只会一个 git merge,遇到复杂场景就抓瞎。今天我把三个核心工具——cherry-pick、rebase、merge——掰开揉碎讲清楚。尤其是 rebase,用好了是神器,用错了是灾难。
12.1 git cherry-pick:精准摘取,不拖泥带水
先说说 cherry-pick。这名字挺形象——就像从一棵树上摘一颗樱桃,只拿你想要的。
场景一:紧急修复
假设你在 feature 分支上开发新功能,突然线上有个 bug 要修。你在 master 上修好了,但 feature 分支也想同步这个修复。怎么办?
# 在 master 上找到修复 bug 的 commit
git log --oneline
# 输出: a1b2c3d fix: 修复登录超时问题
# 切换到 feature 分支
git checkout feature
# 只摘取这个 commit
git cherry-pick a1b2c3d
嗯,就这么简单。只拿一个 commit,不拉整个分支。
场景二:选择性合并
我在项目中遇到过这种情况:同事在 dev 分支上提交了 10 个 commit,但只有 3 个是我们要的。用 merge 会把全部带过来,用 cherry-pick 就精准多了。
# 摘取多个 commit(按时间顺序)
git cherry-pick commitA commitB commitC
# 或者摘取一段连续的 commit
git cherry-pick commitA..commitC
12.2 git rebase vs git merge:两条路,两种哲学
这是 Git 世界里最经典的二选一。说白了,merge 是「保留历史」,rebase 是「美化历史」。
merge 的做法:
# 在 feature 分支上合并 master
git checkout feature
git merge master
结果:产生一个 merge commit,把两条分支的历史「缝合」在一起。历史记录里能看到分叉和合并点。
rebase 的做法:
# 在 feature 分支上变基到 master
git checkout feature
git rebase master
结果:把 feature 分支的 commit「移植」到 master 的最新提交之后。历史变成一条直线,没有分叉。
核心区别:
- merge:保留真实历史,适合公共分支
- rebase:重写历史,让提交线更干净,适合个人分支
你想想看,为什么会有这两种选择?
我个人习惯是:公共分支用 merge,个人分支用 rebase。这样既保证了团队协作的稳定性,又让个人开发体验更清爽。
12.3 rebase 黄金法则:永远不要 rebase 公共分支
这条法则,我建议你刻在脑子里。
为什么?
rebase 会重写 commit 的哈希值。如果你 rebase 了一个已经被其他人拉取的分支,那么别人的本地历史就和远程对不上了。结果就是:冲突不断,谁也推不上去。
我曾经见过一个团队,有人 rebase 了 master 分支。结果全组人花了半天时间才把历史修复回来。嗯,从那以后,我们团队就立了规矩:公共分支只准 merge,不准 rebase。
黄金法则总结:
- ✅ 可以对 尚未推送 的个人分支做 rebase
- ✅ 可以对 只有你自己在用的 分支做 rebase
- ❌ 绝对不要对 master、develop、release 等公共分支做 rebase
- ❌ 绝对不要对 已经推送到远程且别人拉取过的 分支做 rebase
12.4 实战抉择:什么时候用什么?
| 场景 | 推荐操作 | 原因 |
|---|---|---|
| 合并公共分支(如 feature → develop) | merge | 保留完整历史,方便回溯 |
| 同步最新代码到个人分支 | rebase | 保持提交线整洁,避免多余 merge commit |
| 只想要某个特定 commit | cherry-pick | 精准摘取,不引入其他变更 |
| 整理本地未推送的 commit | rebase -i | 交互式变基,可以合并、修改、删除 commit |
| 修复线上 bug 并同步到多个分支 | cherry-pick | 避免 merge 带来的大量冲突 |
12.5 交互式 rebase:整理 commit 的利器
说到 rebase,不能不提 git rebase -i。这玩意儿能让你对 commit 做各种操作:合并、修改、删除、重排序。
# 整理最近 3 个 commit
git rebase -i HEAD~3
打开编辑器后,你会看到类似这样的内容:
pick a1b2c3d feat: 添加登录功能
pick e4f5g6h fix: 修复登录按钮样式
pick i7j8k9l feat: 完善登录页面
# 把第二个 commit 合并到第一个
# 把 pick 改成 squash 或 s
我一般这样用:开发时随便提交,反正都是「草稿」。等开发完了,用 rebase -i 把零散的 commit 合并成几个有意义的提交。这样推上去后,同事 review 起来也舒服。
小技巧:rebase -i 之前,先用 git log 看清楚要操作的 commit 范围。搞错了可以用 git rebase --abort 撤销。
12.6 冲突处理:rebase 和 merge 的差异
冲突是绕不开的。但 rebase 和 merge 处理冲突的方式不一样。
merge 冲突:一次性解决所有冲突,然后提交一个 merge commit。
rebase 冲突:每个 commit 都可能产生冲突,需要逐个解决。解决完一个,用 git rebase --continue 继续。
# 解决完当前冲突后
git add .
git rebase --continue
# 如果觉得搞砸了
git rebase --abort
我个人觉得,rebase 的冲突处理更「精细」。因为每个 commit 的冲突范围小,容易定位问题。但如果你有几十个 commit 要 rebase,那确实挺折磨人的。
12.7 知识体系图
12.8 避坑指南
最后,分享几个我踩过的坑:
- 不要用 rebase 替代 merge——两者各有用途,不是替代关系。
- cherry-pick 后记得测试——因为上下文可能不同,代码不一定能直接跑通。
- rebase 前先备份——可以用
git branch backup创建一个备份分支,万一搞砸了还能恢复。 - 多人协作时,先沟通再 rebase——我曾经 rebase 了一个同事正在开发的分支,结果他推代码时全是冲突。嗯,从那以后我学会了先问一句「这个分支还有别人在用吗?」
一句话总结:
cherry-pick 是「狙击枪」,rebase 是「美容师」,merge 是「缝合匠」。选对工具,事半功倍。
公众号:蓝海资料掘金营,微信deep3321