Skip to content

Merge vs Rebase

概述

合并(Merge)和变基(Rebase)是 Git 中整合分支修改的两种主要方式。理解它们的区别和适用场景对于选择正确的策略至关重要。

两者区别

工作原理

Merge(合并)

# 合并保留分支历史,创建合并提交

      A --- B --- C --- M  (main)
             \         /
              D --- E  (feature)

# M 是合并提交,有两个父提交

Rebase(变基)

# 变基重写历史,线性提交

      A --- B --- C --- D' --- E'  (main, feature)

# D' 和 E' 是新的提交,哈希值已改变

历史记录

bash
# 合并后的历史
git log --oneline --graph
*   a1b2c3d (HEAD -> main) Merge branch 'feature'
|\
| * e5f6g7h (feature) Add feature
* | d4e5f6g Update main
|/
* b2c3d4e Initial commit

# 变基后的历史
git log --oneline --graph
* f6g7h8i (HEAD -> feature) Add feature
* e5f6g7h Update main
* d4e5f6g Add feature
* b2c3d4e Initial commit

操作可逆性

bash
# 合并:可以轻松撤销
git merge feature
git reset --hard HEAD~1  # 撤销合并

# 变基:较难撤销(需要 reflog)
git rebase main
git reset --hard ORIG_HEAD  # 使用 ORIG_HEAD

各自优缺点

Merge 优点

优点说明
保留完整历史可以看到分支的创建和合并过程
操作安全不改变已有提交,不会丢失代码
易于理解团队成员容易理解分支结构
可撤销可以轻松撤销合并
适合公共分支不会影响其他开发者的工作

Merge 缺点

缺点说明
历史复杂大量合并提交使历史难以阅读
提交分散同一功能的提交可能分散在不同分支
bisect 困难使用 git bisact 时可能遇到合并提交

Rebase 优点

优点说明
历史整洁线性历史,易于阅读和理解
提交有序同一功能的提交连续排列
易于调试git bisect 更有效
无合并提交减少不必要的合并提交

Rebase 缺点

缺点说明
改变历史提交哈希改变,可能影响他人
风险较高操作不当可能丢失提交
不适合公共分支会造成协作问题
冲突处理复杂每个提交可能都需要解决冲突

使用场景选择

选择 Merge 的场景

bash
# 1. 合并公共分支
git checkout main
git merge feature

# 2. 保留分支历史
git merge --no-ff feature

# 3. 团队协作
# 多人同时在分支上工作时

# 4. 发布分支合并
git checkout release
git merge develop

选择 Rebase 的场景

bash
# 1. 本地功能分支同步
git checkout feature
git rebase main

# 2. 清理提交历史
git rebase -i main

# 3. 提交前整理
# 将多个小提交合并为一个有意义的提交

# 4. 个人开发分支
# 只有自己在使用的分支

决策流程图

开始

  ├─ 分支是否已推送到远程?
  │   │
  │   ├─ 是 ──→ 使用 Merge
  │   │
  │   └─ 否 ──→ 分支是否只有你一个人使用?
  │               │
  │               ├─ 是 ──→ 可以使用 Rebase
  │               │
  │               └─ 否 ──→ 使用 Merge

  └─ 是否需要保留分支历史?

      ├─ 是 ──→ 使用 Merge (--no-ff)

      └─ 否 ──→ 可以使用 Rebase

最佳实践建议

团队协作规范

bash
# 规则 1:公共分支只接受合并
# main、develop 等公共分支

# 规则 2:功能分支可以变基
# 在合并前整理提交历史

# 规则 3:已推送的分支谨慎变基
# 如果必须变基,需要通知团队

# 规则 4:使用 --force-with-lease
git push --force-with-lease origin feature

功能分支工作流

bash
# 推荐的混合使用方式

# 1. 创建功能分支
git checkout -b feature main

# 2. 开发并提交
git add .
git commit -m "WIP: Add feature"

# 3. 定期同步主分支(使用 merge)
git fetch origin
git merge origin/main
# 或使用 rebase(如果分支未推送)
git rebase origin/main

# 4. 完成功能后整理提交
git rebase -i main
# 合并 WIP 提交,修改提交信息

# 5. 合并到主分支
git checkout main
git merge --no-ff feature
# 或使用 squash
git merge --squash feature

Pull Request 工作流

bash
# GitHub/GitLab PR 工作流

# 1. 创建功能分支并推送
git checkout -b feature main
git push -u origin feature

# 2. 创建 Pull Request

# 3. 代码审查期间同步主分支
git fetch origin
git merge origin/main
# 或
git rebase origin/main
git push --force-with-lease origin feature

# 4. 审查通过后合并
# 通过 Web 界面选择合并方式:
# - Create a merge commit
# - Squash and merge
# - Rebase and merge

合并策略选择

bash
# 功能分支合并到 develop
git checkout develop
git merge --no-ff feature    # 保留分支历史

# 发布分支合并到 main
git checkout main
git merge --no-ff release    # 保留分支历史

# 热修复分支合并
git checkout main
git merge --no-ff hotfix     # 保留分支历史
git checkout develop
git merge --no-ff hotfix     # 同步到开发分支

# 本地分支整理
git checkout feature
git rebase -i main           # 清理提交历史

常见问题

变基后推送失败

bash
# 错误:远程有新提交
! [rejected]        feature -> feature (non-fast-forward)

# 解决方案 1:先合并远程变更
git pull --rebase origin feature
git push origin feature

# 解决方案 2:强制推送(谨慎使用)
git push --force-with-lease origin feature

合并后想改用变基

bash
# 撤销合并
git reset --hard ORIG_HEAD

# 改用变基
git checkout feature
git rebase main

变基后想改用合并

bash
# 使用 reflog 找到变基前的状态
git reflog

# 恢复到变基前
git reset --hard HEAD@{n}

# 改用合并
git checkout main
git merge feature

总结

特性MergeRebase
历史记录保留分支历史线性历史
提交哈希不改变改变
安全性中等
公共分支适合不适合
提交整理不支持支持
冲突处理一次性可能多次

选择建议

  • 公共分支:始终使用 Merge
  • 个人分支:可以使用 Rebase
  • 已推送分支:优先使用 Merge
  • 提交整理:使用交互式 Rebase
  • 团队协作:制定明确的规范

下一步

学习完 Merge vs Rebase 后,建议继续学习: