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
注意:cherry-pick 会生成新的 commit,哈希值不同。这意味着 Git 会认为这是两个不同的提交。如果后续再 merge 整个分支,可能会产生冲突。

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 知识体系图

Git 高级合并知识体系 git cherry-pick git rebase git merge 精准摘取 只拿特定 commit 不引入其他变更 生成新哈希值 重写历史 提交线变直线 交互式整理 commit ⚠️ 不可用于公共分支 保留历史 产生 merge commit 保留分叉结构 适合公共分支 黄金法则:永远不要 rebase 公共分支 个人分支用 rebase,公共分支用 merge,精准需求用 cherry-pick

12.8 避坑指南

最后,分享几个我踩过的坑:

  • 不要用 rebase 替代 merge——两者各有用途,不是替代关系。
  • cherry-pick 后记得测试——因为上下文可能不同,代码不一定能直接跑通。
  • rebase 前先备份——可以用 git branch backup 创建一个备份分支,万一搞砸了还能恢复。
  • 多人协作时,先沟通再 rebase——我曾经 rebase 了一个同事正在开发的分支,结果他推代码时全是冲突。嗯,从那以后我学会了先问一句「这个分支还有别人在用吗?」

一句话总结:

cherry-pick 是「狙击枪」,rebase 是「美容师」,merge 是「缝合匠」。选对工具,事半功倍。


公众号:蓝海资料掘金营,微信deep3321