Appearance
变基(Rebase)
变基(Rebase)是 Git 中另一种整合分支改动的方式。与 Merge 不同,Rebase 通过重新应用提交来创建线性历史。
变基的原理与工作方式
Rebase 的核心思想是:将一系列提交"移动"到新的基础上。
变基前:
A ← B ← C ← D (main)
\
E ← F (feature)
git rebase main(在 feature 分支上执行)
变基后:
A ← B ← C ← D (main)
\
E' ← F' (feature,新的提交对象)变基的过程:
- 找到 feature 和 main 的共同祖先(C)
- 保存 feature 分支上共同祖先之后的所有提交(E、F)
- 将 feature 指向 main 的最新提交(D)
- 在 D 之后依次重新应用之前保存的提交,生成新提交(E'、F')
注意:E' 和 F' 是全新的 Commit 对象(SHA-1 不同),只是内容相同。
git rebase 基本变基
bash
# 在 feature 分支上,将基础变更到 main
git switch feature
git rebase main
# 或者一步完成
git rebase main feature变基后,通常再切回 main 做快进合并:
bash
git switch main
git merge feature # Fast-forward,因为 feature 已经在 main 的前面结果是干净的线性历史。
git rebase --onto 精确变基
--onto 可以将提交从一个分支移动到完全不同的位置:
bash
# 语法:git rebase --onto <新基础> <旧基础> [<分支>]
# 将 server 分支上,从 client 分叉后的提交,变基到 main
git rebase --onto main server client场景示例:
A ← B ← C ← D (main)
\
E ← F (server)
\
G ← H (client)
# 目标:只把 client 相对于 server 的部分(G、H)移到 main 上
git rebase --onto main server client
结果:
A ← B ← C ← D ← G' ← H' (client)
\
E ← F (server)交互式变基 git rebase -i
交互式变基让你可以对一系列提交进行重写历史,是清理提交历史的强大工具。
bash
# 交互式变基最近 3 个提交
git rebase -i HEAD~3
# 交互式变基到某个提交之后
git rebase -i abc123
# 交互式变基到根提交
git rebase -i --root执行后会打开编辑器,显示提交列表:
pick a1b2c3d feat: 添加登录页面
pick e4f5g6h fix: 修复登录样式
pick i7j8k9l feat: 添加注册功能
# Rebase abc..def onto ghi (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# d, drop <commit> = remove commitpick:保留提交
pick a1b2c3d feat: 添加登录页面保持该提交不变,原样保留。
reword:修改提交信息
reword a1b2c3d feat: 添加登录页面(修改这个提交的信息)保留提交内容,但暂停让你修改提交信息。
edit:暂停编辑
edit a1b2c3d feat: 添加登录页面应用此提交后暂停,让你修改文件内容或拆分提交,然后 git rebase --continue。
squash:合并到上一个提交
pick a1b2c3d feat: 添加登录页面
squash e4f5g6h fix: 修复登录样式 ← 合并到上一个 pick 的提交
squash i7j8k9l chore: 清理注释 ← 继续合并合并时会打开编辑器让你修改合并后的提交信息。
fixup:合并但丢弃信息
pick a1b2c3d feat: 添加登录页面
fixup e4f5g6h fix: 修复登录样式 ← 合并,但直接丢弃此提交信息与 squash 类似,但直接使用上一个提交的信息,不打开编辑器。
drop:删除提交
pick a1b2c3d feat: 添加登录页面
drop e4f5g6h fix: 临时调试代码 ← 删除此提交
pick i7j8k9l feat: 添加注册功能删除该提交(该提交的代码改动也会消失)。
reorder:调整提交顺序
直接在编辑器中移动行,就可以调整提交顺序:
# 交换两个提交的顺序
pick i7j8k9l feat: 添加注册功能 ← 把这行移到前面
pick a1b2c3d feat: 添加登录页面git rebase --continue / --abort / --skip
bash
# 解决冲突后,继续 rebase
git add .
git rebase --continue
# 放弃整个 rebase,恢复到 rebase 前的状态
git rebase --abort
# 跳过当前出现冲突的提交,继续 rebase
git rebase --skipfixup + autosquash 工作流
这是一种高效的提交清理工作流:
bash
# 开发过程中,创建 fixup 提交
git commit -m "feat: 添加登录功能"
# ... 发现 bug,修复它 ...
git commit --fixup <feat 提交的 SHA-1>
# 或者用别名
git add .
git commit -m "fixup! feat: 添加登录功能"
# 最后,使用 autosquash 自动整理
git rebase -i --autosquash HEAD~5
# Git 会自动把 fixup 提交放到对应 pick 的下面Merge vs Rebase 的选择策略
使用 Merge 的场景
- 合并公共分支(main、develop)时
- 需要保留完整的分支历史记录时
- 已推送到远程、有多人使用的分支
使用 Rebase 的场景
- 在推送前,整理本地功能分支的提交历史
- 同步上游最新改动(
git pull --rebase) - 需要线性历史(更容易
git bisect)
黄金法则
不要对已推送到公共仓库的分支执行 rebase!
Rebase 会重写历史(生成新的 SHA-1),如果其他人的本地仓库已有这些提交,rebase 后的推送(即使是 force push)会导致他们的仓库混乱。
只对本地/私有分支使用 rebase:
✅ git rebase main feature(本地功能分支)
✅ git pull --rebase(个人工作区同步)
❌ git rebase main(当 main 已推送且有人在协作时)实用场景
bash
# 场景1:开发完功能,推送前整理提交
git rebase -i origin/main
# 场景2:同步主线最新代码,保持线性历史
git switch feature
git fetch origin
git rebase origin/main
# 场景3:将功能合并到主线(clean merge)
git switch feature
git rebase main # 先变基,解决冲突
git switch main
git merge --ff-only feature # 快进合并,确保线性总结
| 对比项 | Merge | Rebase |
|---|---|---|
| 历史形状 | 非线性(有分叉) | 线性 |
| 原始提交 | 保留 | 重写(新 SHA-1) |
| 适合场景 | 合并公共分支 | 整理本地历史 |
| 安全性 | 总是安全 | 不能用于已公开的提交 |
| 可读性 | 保留完整历史 | 历史更简洁 |
理解并正确使用 Rebase,能让你的 Git 历史保持清晰整洁,是专业开发者的重要技能。