git merge 和 git rebase 怎么选?一张图讲清差别
merge 保留合并记录但历史有分叉,rebase 让历史线性干净但会改写提交。本文用历史图形讲透两者差别,给你"什么场景用哪个"的清晰决策。
场景:团队协作要把功能分支合并回主分支,或者想把本地代码同步到远程最新。用 git merge 还是 git rebase?这个经典之问,下面用历史图形讲透。
merge:保留分叉,生成合并提交
A---B---C main
\
D---E feature
执行 git checkout main && git merge feature 后:
A---B---C---F(main)
\ /
D---E
F 是一个 merge 提交,记录"把 feature 合进来了"。历史保留了真实的分叉结构。
rebase:线性历史
git checkout feature && git rebase main
把 feature 的提交重新放到 main 最新之上:
D'---E' (feature, 哈希变了)
/
A---B---C (main)
之后若快进合并 main,历史是一条直线:
A---B---C---D'---E'
干净线性,但没有保留"这曾是个 feature 分支"的合并记录。
关键区别一览
| git merge | git rebase | |
|---|---|---|
| 历史形态 | 有分叉+merge提交 | 线性干净 |
| 改写提交 | 不改 | 改写(哈希变) |
| 保留原始分叉信息 | ✅ | ❌ |
| 共享分支上使用 | 安全 | 危险 |
| 冲突处理 | 一次 | 可能多次 |
| 适合 | 保留完整历史 | 整理私有提交 |
怎么选(决策)
用 merge(推荐保留历史):
- 功能分支完成,合并回公共主分支
- 想保留"这个功能曾并行开发"的记录
- 分支已 push 并多人使用
用 rebase(推荐整理本地):
- 本地有几个杂乱提交想整理干净
git pull --rebase同步远程最新(避免多余 merge)- 想让提交历史线性清晰
两者结合的标准工作流
# 1. 在 feature 分支,先同步远程最新到本地(用 rebase 让本地干净)
git pull --rebase origin main
# 2. 功能开发、提交
git add .
git commit -m "feat: xxx"
# 3. 合并回 main(用 merge 保留合并记录)
git checkout main
git merge feature
规则总结:本地整理用 rebase,汇入公共分支用 merge;不要对共享分支 rebase。
冲突处理的差别
- merge 冲突:解决一次,产生一个 merge 提交
- rebase 冲突:每个被重放的提交都可能冲突,需逐个解决,用
git rebase --continue/--abort
一句话速记
保留历史、合并公共分支用 merge;整理私有提交、想线性干净用 rebase;别对共享分支 rebase。
?
常见问题 FAQ
rebase 会改写提交,安全吗?
只对自己本地未共享的提交做 rebase 是安全的。但绝不要对"已 push 到远程且多人使用"的分支 rebase,那会改写共享历史导致协作者冲突。
pull --rebase 和 merge 默认 pull 选哪个?
团队常用 pull --rebase 让本地提交干净叠到远程之上、历史线性;若团队更看重保留完整合并信息,用默认 merge。关键看团队约定。
rebase 后提交会变多还是变少?
提交数量通常不变(重放到新基点),但每个被变基的提交哈希会变(因为父提交变了)。可用交互式 rebase -i 合并提交使其变少。
merge 会生成额外的 merge 提交吗?
只有两个分支真正分叉(都有对方没有的提交)时才生成 merge 提交;若一个分支是另一个的直接祖先,会做 fast-forward 快进,不产生 merge 提交。