Git 完全指南 / 11 - 变基进阶:interactive rebase、autosquash、onto
第十一章:变基进阶
交互式变基是 Git 中最强大的历史重写工具,掌握它可以让你的提交历史清晰优雅。
11.1 交互式变基(Interactive Rebase)
11.1.1 基本语法
# 对最近 N 个提交进行交互式变基
$ git rebase -i HEAD~5
# 基于某个提交
$ git rebase -i abc1234
# 对整个分支进行变基
$ git rebase -i main
11.1.2 交互式变基指令
执行 git rebase -i HEAD~5 后,编辑器会打开:
pick abc1234 feat: add user model
pick def5678 feat: add user controller
pick ghi9012 fix: typo in controller
pick jkl3456 refactor: clean up user model
pick mno7890 feat: add user tests
可用指令:
| 指令 | 简写 | 说明 |
|---|---|---|
pick | p | 保留该提交 |
reword | r | 保留提交但修改提交信息 |
edit | e | 保留提交但暂停以便修改 |
squash | s | 与前一个提交合并,保留两者的提交信息 |
fixup | f | 与前一个提交合并,丢弃此提交的信息 |
exec | x | 在该位置执行 shell 命令 |
drop | d | 删除该提交 |
break | b | 在此处暂停 |
label | l | 为当前 HEAD 添加标签 |
reset | t | 重置 HEAD 到标签 |
merge | m | 创建合并提交 |
11.1.3 压缩提交示例
# 原始提交
pick abc1234 feat: add user model
squash def5678 fix: typo in user model
squash ghi9012 feat: add user validation
# 结果:三个提交合并为一个
# 编辑器让你编辑合并后的提交信息
feat: add user model with validation
11.1.4 调整提交顺序
# 重新排列提交顺序(交换行即可)
pick ghi9012 feat: add user tests # 原来在第三个
pick abc1234 feat: add user model # 原来在第一个
pick def5678 feat: add user controller # 原来在第二个
⚠️ 调整顺序可能会导致冲突,需要手动解决。
11.1.5 修改提交内容
# 使用 edit 指令暂停在某个提交
edit abc1234 feat: add user model
pick def5678 feat: add user controller
# Git 会暂停
Stopped at abc1234... feat: add user model
# 修改文件
$ vim src/user/model.js
# 追加修改到当前提交
$ git add -A
$ git commit --amend
# 继续变基
$ git rebase --continue
# 或跳过某个提交
$ git rebase --skip
# 或中止变基(回到原始状态)
$ git rebase --abort
11.2 Autosquash(自动压缩)
--autosquash 让 fixup 和 squash 提交自动与目标提交配对。
11.2.1 使用 fixup 提交
# 正常开发
$ git commit -m "feat: add login page"
# 后续发现需要修复,创建 fixup 提交
$ git commit --fixup=abc1234
# 提交信息自动变为:fixup! feat: add login page
# 或使用 squash
$ git commit --squash=abc1234
# 提交信息自动变为:squash! feat: add login page
11.2.2 自动整理
# 启用 autosquash 进行交互式变基
$ git rebase -i --autosquash main
# 交互式界面会自动排列:
pick abc1234 feat: add login page
fixup def5678 fixup! feat: add login page # 自动排在目标后面
pick ghi9012 feat: add register page
11.2.3 配置自动启用
# 全局启用 autosquash
$ git config --global rebase.autosquash true
# 之后 git rebase -i 会自动使用 --autosquash
11.3 --onto 参数
--onto 允许你精确控制变基的目标基础点。
11.3.1 基本语法
$ git rebase --onto <newbase> <upstream> <branch>
11.3.2 常见用法
移植分支到新的基础点
场景:feature 分支是从 develop 拉出的,现在需要基于 main 重新变基
main: M1 → M2 → M3
develop: D1 → D2 → D3
feature: F1 → F2 → F3
# 将 feature 基于 main 重新变基
$ git rebase --onto main develop feature
# 结果:
main: M1 → M2 → M3
feature: F1' → F2' → F3'
删除中间提交
# 删除第二个到第四个提交之间的所有提交
$ git rebase --onto HEAD~4 HEAD~3 HEAD
摘取分支范围
# 只将 feature 中不属于 develop 的提交移到 main
$ git rebase --onto main develop feature
11.4 变基工作流
11.4.1 功能开发工作流
# 1. 从主分支创建功能分支
$ git switch -c feature/auth main
# 2. 开发过程中产生多个提交
$ git commit -m "feat: add auth controller"
$ git commit -m "fix: typo in controller"
$ git commit -m "feat: add auth tests"
$ git commit -m "fix: fix test assertions"
$ git commit -m "refactor: clean up auth logic"
# 3. 合并前整理提交历史
$ git rebase -i main
# 编辑器中操作:
pick abc1234 feat: add auth controller
squash def5678 fix: typo in controller
pick ghi9012 feat: add auth tests
squash jkl3456 fix: fix test assertions
squash mno7890 refactor: clean up auth logic
# 4. 编写清晰的最终提交信息
feat: implement authentication module
- Add auth controller with login/register endpoints
- Implement JWT token generation and validation
- Add comprehensive test coverage
- Clean up auth logic and error handling
# 5. 推送并创建 PR
$ git push origin feature/auth
11.4.2 同步主分支更新
# 1. 获取主分支最新代码
$ git fetch origin
# 2. 将功能分支变基到最新主分支
$ git rebase origin/main
# 3. 解决冲突(如有)
$ git rebase --continue
# 4. 强制推送更新后的分支
$ git push --force-with-lease origin feature/auth
11.5 变基冲突处理
# 变基过程中遇到冲突
$ git rebase -i main
CONFLICT (content): Merge conflict in src/auth.js
# 查看冲突状态
$ git status
# 方法 1:手动解决
$ vim src/auth.js # 编辑冲突
$ git add src/auth.js
$ git rebase --continue
# 方法 2:使用工具
$ git mergetool
# 方法 3:使用某个版本
$ git checkout --ours src/auth.js # 保留主分支版本
$ git checkout --theirs src/auth.js # 使用功能分支版本
$ git add src/auth.js
$ git rebase --continue
# 中止变基,回到原始状态
$ git rebase --abort
# 跳过当前提交
$ git rebase --skip
11.6 变基 vs 合并决策
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 个人功能分支 → 主分支 | Rebase | 保持线性历史 |
| 多人协作的公共分支 | Merge | 不重写他人历史 |
| 同步主分支到功能分支 | Rebase | 便于最终合并 |
| 回顾特定功能的所有修改 | Merge | 保留合并记录 |
| 发布分支合并到主分支 | Merge | 记录发布点 |
⚠️ 黄金法则:永远不要 rebase 已经推送到远程的公共分支!
业务场景
| 场景 | 推荐方案 |
|---|---|
| PR 提交前清理历史 | git rebase -i 压缩和整理 |
| 同步上游代码 | git rebase origin/main |
| 将功能移到新的基础 | git rebase --onto |
| 修复历史中的错误提交 | git rebase -i + edit/reword |
| 持续开发中的修复 | git commit --fixup + --autosquash |