Git Rebase 详解:概念、原理与实战示例

418 阅读5分钟

Git Rebase 详解:概念、原理与实战示例

什么是 Git Rebase?

Git rebase(变基)是一种重写提交历史的操作,它可以将一个分支的修改"重新应用"到另一个分支上。与 git merge 不同,rebase 会创建更线性、更整洁的提交历史。

核心概念对比:

操作合并方式历史记录适用场景
git merge创建新的合并提交保留分支结构(树状)公共分支合并
git rebase重写提交历史线性历史(单一线程)本地分支整理、清理提交历史

Rebase 工作原理

  1. 找到共同祖先:确定两个分支的最近共同提交
  2. 保存差异:提取当前分支的所有新提交(作为补丁)
  3. 重置分支指针:将当前分支重置到目标分支的最新提交
  4. 重新应用提交:将保存的补丁按顺序应用到目标分支上
初始状态:
      A---B---C  feature
     /
D---E---F---G    main

执行 `git rebase main` 后:
              A'---B'---C'  feature
             /
D---E---F---G    main

注意:原始提交 A/B/C 被新提交 A'/B'/C' 替代(内容相同但哈希值不同)

实战示例:使用 Rebase

示例场景

假设我们有两个分支:

  • main 分支:有 2 个提交
  • feature 分支:从 main 分支创建,有 3 个提交
# 查看提交历史
git log --all --graph --oneline

# 输出:
* 38f7a5b (feature) 功能C
* 82d1d3c 功能B
* efc1a2c 功能A
| * 4a9b21d (main) 主功能2
| * 7c2e8f1 主功能1
|/
* 2d3f4a5 初始提交

基础 Rebase 操作

  1. 将 feature 分支变基到 main 分支
git checkout feature
git rebase main
  1. 查看变基后的历史
git log --all --graph --oneline

# 输出:
* 5c1a2e3 (feature) 功能C
* 9b8d7f6 功能B
* a4f3e2d 功能A
* 4a9b21d (main) 主功能2
* 7c2e8f1 主功能1
* 2d3f4a5 初始提交

现在历史变为线性结构,feature 分支的提交被"移动"到 main 分支顶部

交互式 Rebase(高级用法)

交互式 rebase 允许你修改提交历史:

git rebase -i HEAD~3  # 编辑最近3个提交

编辑器会打开:

pick a4f3e2d 功能A
pick 9b8d7f6 功能B
pick 5c1a2e3 功能C

# 可用的命令:
# p, pick = 使用提交
# r, reword = 使用提交但修改提交信息
# e, edit = 使用提交,但暂停修改
# s, squash = 使用提交,但合并到前一个提交
# f, fixup = 类似"squash",但丢弃提交信息
# d, drop = 删除提交
常见操作示例:
  1. 合并提交(将多个提交合并为一个)
pick a4f3e2d 功能A
squash 9b8d7f6 功能B
squash 5c1a2e3 功能C
  1. 修改提交信息
reword a4f3e2d 新功能A描述
pick 9b8d7f6 功能B
pick 5c1a2e3 功能C
  1. 删除提交
pick a4f3e2d 功能A
drop 9b8d7f6 功能B  # 删除此提交
pick 5c1a2e3 功能C

解决 Rebase 冲突

当 rebase 过程中出现冲突时:

  1. Git 会暂停 rebase 并标记冲突文件
  2. 手动解决冲突
  3. 标记冲突已解决:
git add <解决的文件>
  1. 继续 rebase:
git rebase --continue
  1. 如果无法解决,可以中止 rebase:
git rebase --abort

Rebase 最佳实践

  1. 黄金法则:永远不要对公共分支(已推送到远程仓库的分支)进行 rebase

    • 只对本地分支使用 rebase
    • 对公共分支使用 merge
  2. 使用场景

    • 整理本地分支提交历史
    • 将本地分支更新到主分支最新状态
    • 清理功能分支的提交历史(如合并多个小提交)
  3. 工作流程

# 在本地功能分支上
git fetch origin
git rebase origin/main  # 将本地分支变基到远程主分支

# 解决冲突(如果有)
git push origin feature --force-with-lease  # 强制推送更新后的分支

Rebase vs Merge 对比示例

使用 Merge:

git checkout main
git merge feature

历史记录:

*   e1f2g3h (HEAD -> main) Merge branch 'feature'
|\  
| * 5c1a2e3 (feature) 功能C
| * 9b8d7f6 功能B
| * a4f3e2d 功能A
* | 4a9b21d 主功能2
* | 7c2e8f1 主功能1
|/  
* 2d3f4a5 初始提交

使用 Rebase + Merge:

git checkout feature
git rebase main
git checkout main
git merge feature  # 快进合并

历史记录(线性):

* 5c1a2e3 (HEAD -> main, feature) 功能C
* 9b8d7f6 功能B
* a4f3e2d 功能A
* 4a9b21d 主功能2
* 7c2e8f1 主功能1
* 2d3f4a5 初始提交

高级技巧

只 rebase 部分提交

git rebase --onto newbase oldbase feature

示例:

A---B---C---D---E  feature
     \
      F---G  main

# 只移动 D 和 E 到 main
git rebase --onto main C feature

自动解决小冲突

git rebase -Xignore-all-space  # 忽略空格变更
git rebase -Xtheirs           # 自动选择他们的版本

注意事项

  1. 重写历史的风险

    • 已共享的提交不要 rebase
    • 强制推送 (--force-with-lease) 可能影响协作者
  2. 恢复误操作

# 查看操作记录
git reflog

# 重置到 rebase 前的状态
git reset --hard ORIG_HEAD
  1. 使用备份分支
git branch feature-backup feature  # 创建备份分支
git rebase main

总结

Git rebase 是强大的历史重写工具,适合:

  • 创建更整洁的提交历史
  • 本地分支整理
  • 保持线性项目历史

关键原则:

  • 只对未共享的本地提交使用 rebase
  • 公共分支使用 merge
  • 交互式 rebase 前创建备份分支
  • 使用 --force-with-lease 而不是 --force

掌握 rebase 可以显著改善你的 Git 工作流,使项目历史更加清晰易懂!