Skip to content

变基(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,新的提交对象)

变基的过程:

  1. 找到 feature 和 main 的共同祖先(C)
  2. 保存 feature 分支上共同祖先之后的所有提交(E、F)
  3. 将 feature 指向 main 的最新提交(D)
  4. 在 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 commit

pick:保留提交

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 --skip

fixup + 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  # 快进合并,确保线性

总结

对比项MergeRebase
历史形状非线性(有分叉)线性
原始提交保留重写(新 SHA-1)
适合场景合并公共分支整理本地历史
安全性总是安全不能用于已公开的提交
可读性保留完整历史历史更简洁

理解并正确使用 Rebase,能让你的 Git 历史保持清晰整洁,是专业开发者的重要技能。