Git Rebase 详解:概念、原理与实战示例
什么是 Git Rebase?
Git rebase(变基)是一种重写提交历史 的操作,它可以将一个分支的修改"重新应用"到另一个分支上。与 git merge
不同,rebase 会创建更线性、更整洁的提交历史。
核心概念对比:
操作 | 合并方式 | 历史记录 | 适用场景 |
---|---|---|---|
git merge |
创建新的合并提交 | 保留分支结构(树状) | 公共分支合并 |
git rebase |
重写提交历史 | 线性历史(单一线程) | 本地分支整理、清理提交历史 |
Rebase 工作原理
- 找到共同祖先:确定两个分支的最近共同提交
- 保存差异:提取当前分支的所有新提交(作为补丁)
- 重置分支指针:将当前分支重置到目标分支的最新提交
- 重新应用提交:将保存的补丁按顺序应用到目标分支上
css
初始状态:
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 个提交
bash
# 查看提交历史
git log --all --graph --oneline
# 输出:
* 38f7a5b (feature) 功能C
* 82d1d3c 功能B
* efc1a2c 功能A
| * 4a9b21d (main) 主功能2
| * 7c2e8f1 主功能1
|/
* 2d3f4a5 初始提交
基础 Rebase 操作
- 将 feature 分支变基到 main 分支
bash
git checkout feature
git rebase main
- 查看变基后的历史
bash
git log --all --graph --oneline
# 输出:
* 5c1a2e3 (feature) 功能C
* 9b8d7f6 功能B
* a4f3e2d 功能A
* 4a9b21d (main) 主功能2
* 7c2e8f1 主功能1
* 2d3f4a5 初始提交
现在历史变为线性结构,feature 分支的提交被"移动"到 main 分支顶部
交互式 Rebase(高级用法)
交互式 rebase 允许你修改提交历史:
bash
git rebase -i HEAD~3 # 编辑最近3个提交
编辑器会打开:
shell
pick a4f3e2d 功能A
pick 9b8d7f6 功能B
pick 5c1a2e3 功能C
# 可用的命令:
# p, pick = 使用提交
# r, reword = 使用提交但修改提交信息
# e, edit = 使用提交,但暂停修改
# s, squash = 使用提交,但合并到前一个提交
# f, fixup = 类似"squash",但丢弃提交信息
# d, drop = 删除提交
常见操作示例:
- 合并提交(将多个提交合并为一个)
css
pick a4f3e2d 功能A
squash 9b8d7f6 功能B
squash 5c1a2e3 功能C
- 修改提交信息
css
reword a4f3e2d 新功能A描述
pick 9b8d7f6 功能B
pick 5c1a2e3 功能C
- 删除提交
css
pick a4f3e2d 功能A
drop 9b8d7f6 功能B # 删除此提交
pick 5c1a2e3 功能C
解决 Rebase 冲突
当 rebase 过程中出现冲突时:
- Git 会暂停 rebase 并标记冲突文件
- 手动解决冲突
- 标记冲突已解决:
bash
git add <解决的文件>
- 继续 rebase:
bash
git rebase --continue
- 如果无法解决,可以中止 rebase:
bash
git rebase --abort
Rebase 最佳实践
-
黄金法则:永远不要对公共分支(已推送到远程仓库的分支)进行 rebase
- 只对本地分支使用 rebase
- 对公共分支使用 merge
-
使用场景:
- 整理本地分支提交历史
- 将本地分支更新到主分支最新状态
- 清理功能分支的提交历史(如合并多个小提交)
-
工作流程:
bash
# 在本地功能分支上
git fetch origin
git rebase origin/main # 将本地分支变基到远程主分支
# 解决冲突(如果有)
git push origin feature --force-with-lease # 强制推送更新后的分支
Rebase vs Merge 对比示例
使用 Merge:
bash
git checkout main
git merge feature
历史记录:
markdown
* e1f2g3h (HEAD -> main) Merge branch 'feature'
|\
| * 5c1a2e3 (feature) 功能C
| * 9b8d7f6 功能B
| * a4f3e2d 功能A
* | 4a9b21d 主功能2
* | 7c2e8f1 主功能1
|/
* 2d3f4a5 初始提交
使用 Rebase + Merge:
bash
git checkout feature
git rebase main
git checkout main
git merge feature # 快进合并
历史记录(线性):
markdown
* 5c1a2e3 (HEAD -> main, feature) 功能C
* 9b8d7f6 功能B
* a4f3e2d 功能A
* 4a9b21d 主功能2
* 7c2e8f1 主功能1
* 2d3f4a5 初始提交
高级技巧
只 rebase 部分提交
bash
git rebase --onto newbase oldbase feature
示例:
css
A---B---C---D---E feature
\
F---G main
# 只移动 D 和 E 到 main
git rebase --onto main C feature
自动解决小冲突
bash
git rebase -Xignore-all-space # 忽略空格变更
git rebase -Xtheirs # 自动选择他们的版本
注意事项
-
重写历史的风险:
- 已共享的提交不要 rebase
- 强制推送 (
--force-with-lease
) 可能影响协作者
-
恢复误操作:
bash
# 查看操作记录
git reflog
# 重置到 rebase 前的状态
git reset --hard ORIG_HEAD
- 使用备份分支:
bash
git branch feature-backup feature # 创建备份分支
git rebase main
总结
Git rebase 是强大的历史重写工具,适合:
- 创建更整洁的提交历史
- 本地分支整理
- 保持线性项目历史
关键原则:
- 只对未共享的本地提交使用 rebase
- 公共分支使用 merge
- 交互式 rebase 前创建备份分支
- 使用
--force-with-lease
而不是--force
掌握 rebase 可以显著改善你的 Git 工作流,使项目历史更加清晰易懂!