Merge vs Rebase
在 Git 中,merge 和 rebase 是合并分支的两种主要方式。它们的目的相同:将一个分支的更改集成到另一个分支,但实现方式和最终的历史记录截然不同。
1. Git Merge (合并)
merge 是最常见的合并方式。它保留了分支的原始历史,并创建一个新的“合并提交” (Merge Commit)。
工作原理
假设你有 main 分支和 feature 分支:
bash
git checkout main
git merge featureGit 会做两件事:
- 找到两个分支的最近共同祖先。
- 将
feature分支自祖先以来的所有更改,合并到main分支。 - 创建一个新的 Commit(称为 Merge Commit),它有两个父节点。
图解
text
A---B---C feature
/ \
D---E---F-------G main (Merge Commit)优缺点
- 优点:
- 非破坏性:完全保留了历史记录,不会修改现有的 Commit。
- 真实性:忠实地记录了开发的实际发生顺序。
- 简单:操作简单,冲突处理相对直观。
- 缺点:
- 历史混乱:如果分支很多,历史记录会变成复杂的网状结构("Spaghetti History"),难以阅读。
- 噪音:产生大量的 Merge Commit,可能掩盖了实际的代码更改。
2. Git Rebase (变基)
rebase 的意思是“改变基础”。它将当前分支的更改,“重新播放”在目标分支的最新提交之上。
工作原理
bash
git checkout feature
git rebase mainGit 会做以下操作:
- 找到
feature和main的共同祖先。 - 暂时保存
feature分支上的所有更改(Commits)。 - 将
feature分支指向main的最新提交。 - 将保存的更改逐个应用到新的基础之上(可能会产生新的 Hash)。
图解
Rebase 前:
text
A---B feature
/
D---E---F mainRebase 后:
text
A'--B' feature
/
D---E---F main最终看起来就像是 feature 分支是直接从 main 的最新提交 F 开始开发的,历史变成了一条直线。
优缺点
- 优点:
- 线性历史:历史记录非常干净、整洁,像一条直线。
- 易于追踪:没有多余的 Merge Commit,
git log更清晰。
- 缺点:
- 修改历史:它会改变 Commit 的 Hash 值。
- 风险:如果分支已经推送到公共仓库,Rebase 会导致其他人的历史混乱。
- 冲突处理:如果在多个 Commit 中有冲突,可能需要多次解决冲突(每个 Commit 应用时都可能冲突)。
3. 黄金法则 (Golden Rule)
绝不要在公共分支(如 main)上使用 Rebase!
只在你自己的私有分支(尚未推送到远程,或只有你一个人使用的分支)上使用 Rebase 来整理提交。
4. 总结对比
| 特性 | Git Merge | Git Rebase |
|---|---|---|
| 历史形态 | 网状结构,保留分支轨迹 | 线性结构,单一直线 |
| Merge Commit | 有 (除非是 Fast-forward) | 无 |
| Commit Hash | 不变 | 改变 (即便是相同内容的提交) |
| 冲突处理 | 一次性解决 | 可能需要分多次解决 |
| 适用场景 | 公共分支合并,保留完整历史 | 个人分支整理,追求整洁历史 |
什么时候用哪个?
- 使用 Merge:当你想要记录“这里发生了一次合并”时,或者在公共分支上工作时。
- 使用 Rebase:当你想要清理本地提交历史,或者想要将你的功能分支更新到最新的
main代码以便后续合并时(通常是git pull --rebase)。