跳转到内容
关系图谱

Git rebase 详解

6,600 字 25 分钟

属性 1
status
学习中

Git rebase 详解

git rebase 是 Git 中用于重新排列提交历史的强大命令。它的核心功能是将一系列提交「搬移」到另一个基础提交之上,从而产生一条线性的、更整洁的提交历史。它也可以用于交互式编辑提交(squash、reword、拆分等)。

黄金法则

永远不要对已推送到远程公共分支的提交执行 rebase。 rebase 会改写提交历史(生成新的 SHA),这会破坏其他协作者的工作。

基本语法

bash
git rebase [--onto <newbase>] [<upstream>] [<branch>]
git rebase -i [<upstream>]
git rebase --continue
git rebase --abort
git rebase --skip

核心概念

rebase vs merge

这是 Git 中最经典的争论之一。两者都能将分支的修改整合到一起,但方式完全不同。

merge 的结果

rebase 的结果

对比项git mergegit rebase
历史结构保留分支结构(非线性线性历史(无分支痕迹
新提交创建合并提交(merge commit)不创建额外提交(重放已有提交)
原始 SHA保留全部改变(新的 SHA)
安全性安全(不改写历史)改写历史(已推送的提交不可 rebase)
冲突处理一次性解决所有冲突逐个提交解决冲突
适用场景公共分支合并、保留完整上下文整理本地提交、保持线性历史
选择建议
  • 合并公共分支(如将 feature 合入 main)→ 用 merge
  • 同步上游更新到本地分支 → 用 rebase
  • 整理本地提交历史 → 用 rebase -i
  • 不确定用哪个 → 用 merge(更安全)

rebase 的工作原理

git rebase 的内部过程可以分解为以下步骤:

详细过程:

为什么 SHA 会变?

Git 提交的 SHA 是根据内容、父提交、作者、时间等信息计算的哈希值。rebase 改变了父提交(从 C2 变成了 C3),所以即使提交内容不变,SHA 也会不同。

基本用法

将 feature 分支变基到 main

bash
# 方式 1:先切换到 feature 分支
git checkout feature
git rebase main

# 方式 2:直接指定(无需切换分支)
git rebase main feature

同步远程 main 的更新

bash
# 场景:main 有了新提交,feature 分支需要同步

# 方式 1:rebase
git checkout feature
git fetch origin
git rebase origin/main

# 方式 2:pull --rebase(更简洁)
git pull --rebase origin main
设置默认 pull 使用 rebase
bash
# 全局设置
git config --global pull.rebase true

# 单个仓库设置
git config pull.rebase true

设置后 git pull 自动使用 rebase 而不是 merge

--onto:精确控制变基目标

--onto 允许你将一部分提交搬移到另一个基础上,是 rebase 最灵活的用法。

bash
git rebase --onto <newbase> <upstream> [<branch>]

场景 1:将分支从一个基础移到另一个

bash
# feature 分支是从 develop 创建的,现在想移到 main 上
#
# 之前:main → C1 → C2
#        develop → C1 → C3 → C4
#        feature → C1 → C3 → C4 → C5 → C6
#
# 目标:将 C5、C6 移到 main 上

git rebase --onto main develop feature
# 结果:main → C1 → C2 → C5' → C6' (feature)

场景 2:删除中间的提交

bash
# 想删除 C3 这个提交(保留 C4、C5)
# C1 → C2 → C3 → C4 → C5 (HEAD)

git rebase --onto C2 C3
# 结果:C1 → C2 → C4' → C5' (HEAD)
# C3 被跳过了

交互式 rebase(-i

交互式 rebase 是 Git 中最强大的历史整理工具,允许你对提交进行重排序、合并、拆分、编辑、删除等操作。

基本用法

bash
# 交互式编辑最近 N 个提交
git rebase -i HEAD~N

# 交互式编辑从某个提交之后的所有提交
git rebase -i <commit>

# 编辑当前分支上所有不在 main 中的提交
git rebase -i main

交互式编辑器界面

执行后 Git 会打开编辑器,显示类似以下内容:

pick abc1234 feat: 添加用户模型
pick def5678 fix: 修复用户验证
pick ghi9012 feat: 添加登录页面
pick jkl3456 fix: 修复拼写错误
pick mno7890 chore: 更新依赖

# Rebase 123456..mno7890 onto 123456 (5 commands)
#
# Commands:
# p, pick = 使用提交(不做修改)
# r, reword = 使用提交,但修改提交信息
# e, edit = 使用提交,但暂停让你修改内容
# s, squash = 合并到前一个提交,保留提交信息
# f, fixup = 合并到前一个提交,丢弃提交信息
# x, exec = 执行 shell 命令
# b, break = 在此处暂停
# d, drop = 删除提交

操作命令详解

命令简写说明
pickp保留提交不变(默认)
rewordr保留提交,但修改提交信息
edite暂停在该提交,允许修改文件内容或拆分提交
squashs合并到前一个提交,合并两者的提交信息
fixupf合并到前一个提交,丢弃当前提交的信息
execx在该提交后执行一个 shell 命令
breakb在此处暂停 rebase,可用 --continue 继续
dropd删除该提交(也可以直接删除那一行)
labell为当前 HEAD 打标签(用于复杂 rebase)
resett将 HEAD 重置到某个标签
mergem创建合并提交(保留合并历史)

常见操作示例

合并提交(squash)

将多个小提交合并成一个有意义的提交:

bash
git rebase -i HEAD~4

编辑器中修改:

pick abc1234 feat: 添加用户模型
squash def5678 fix: 修复用户验证
squash ghi9012 fix: 修复拼写错误
squash jkl3456 test: 添加用户测试
squash vs fixup
  • squash:合并时会打开编辑器,让你编辑合并后的提交信息(包含所有被合并提交的信息)
  • fixup:合并时直接丢弃当前提交的信息,只保留目标提交的信息

对于修复拼写、格式调整等小修改,用 fixup 更高效。

修改提交信息(reword)

bash
git rebase -i HEAD~3
reword abc1234 feat: 旧的提交信息
pick def5678 feat: 另一个提交
pick ghi9012 fix: 修复

保存后 Git 会依次打开编辑器让你修改标记为 reword 的提交信息。

编辑提交内容(edit)

bash
git rebase -i HEAD~3
edit abc1234 feat: 需要修改内容的提交
pick def5678 feat: 其他提交

保存后 Git 会暂停在 abc1234:

bash
# 修改文件
vim src/user.ts

# 将修改加入到该提交
git add src/user.ts
git commit --amend

# 继续 rebase
git rebase --continue

删除提交(drop)

bash
git rebase -i HEAD~4
pick abc1234 feat: 保留这个
drop def5678 debug: 删除这个调试提交
pick ghi9012 feat: 保留这个
pick jkl3456 feat: 保留这个

重排序提交

直接在编辑器中调换行的顺序即可:

# 原始顺序
pick abc1234 feat: A
pick def5678 feat: B
pick ghi9012 feat: C

# 调整后
pick ghi9012 feat: C
pick abc1234 feat: A
pick def5678 feat: B
重排序可能产生冲突

如果提交之间有依赖关系(后面的提交修改了前面提交创建的文件),重排序可能导致冲突。

拆分提交(split)

使用 edit 暂停后,将一个大提交拆分为多个小提交:

bash
git rebase -i HEAD~3
# 将目标提交标记为 edit

# rebase 暂停后
git reset HEAD~1
# 所有修改回到工作区

# 分批提交
git add src/model/
git commit -m "feat: 数据模型"

git add src/api/
git commit -m "feat: API 接口"

git add tests/
git commit -m "test: 添加测试"

# 继续 rebase
git rebase --continue

使用 exec 自动运行测试

bash
git rebase -i HEAD~5
pick abc1234 feat: 功能 A
exec npm test
pick def5678 feat: 功能 B
exec npm test
pick ghi9012 fix: 修复
exec npm test
确保每个提交都能通过测试

在每个提交后插入 exec npm test(或其他测试命令),如果测试失败,rebase 会暂停,让你修复问题。这有助于确保每个提交都是可构建、可测试的。

--autosquash:自动整理 fixup 提交

配合 git commit --fixupgit commit --squash 使用,自动将修复提交合并到目标提交。

bash
# 1. 正常提交
git commit -m "feat: 用户登录"

# 2. 发现需要修复上面的提交
git add src/auth.ts
git commit --fixup abc1234   # 自动生成消息 "fixup! feat: 用户登录"

# 3. 交互式 rebase 时自动排列
git rebase -i --autosquash main
# fixup 提交会自动移到目标提交下方并标记为 fixup
默认启用 autosquash
bash
git config --global rebase.autoSquash true

设置后 git rebase -i 自动启用 --autosquash,无需每次手动添加。

处理冲突

rebase 过程中,每个提交都可能产生冲突(因为是逐个重放的)。

冲突解决流程

实际操作

bash
# 1. 开始 rebase
git rebase main
# CONFLICT (content): Merge conflict in src/main.ts

# 2. 解决冲突
# 编辑冲突文件,删除冲突标记 <<<<<<<, =======, >>>>>>>

# 3. 标记冲突已解决
git add src/main.ts

# 4. 继续 rebase(不要用 git commit!)
git rebase --continue

# 如果同一个提交还有其他冲突,重复步骤 2-4

--abort vs --skip vs --quit

命令效果
git rebase --continue冲突解决后继续重放下一个提交
git rebase --abort完全取消 rebase,恢复到 rebase 前的状态
git rebase --skip跳过当前有冲突的提交,继续下一个
git rebase --quit退出 rebase,保留已成功重放的提交
--skip 会丢失提交

--skip完全跳过当前提交,该提交的所有修改都不会包含在最终结果中。只在你确定这个提交不需要时使用。

减少冲突的技巧

频繁 rebase 减少冲突

不要等到 main 分支有了几十个新提交后才 rebase。养成每天或每几个提交就同步一次的习惯:

bash
git fetch origin
git rebase origin/main
使用 rerere 自动记住冲突解决方案
bash
# 启用 rerere(Reuse Recorded Resolution)
git config --global rerere.enabled true

启用后,Git 会记住你解决冲突的方式。如果下次遇到相同的冲突(比如 rebase 失败重试),Git 会自动应用之前的解决方案。

高级用法

--rebase-merges:保留合并历史

默认的 rebase 会将合并提交扁平化(丢失分支合并的结构)。使用 --rebase-merges 可以保留合并提交:

bash
git rebase --rebase-merges main

--update-refs:自动更新中间分支引用

当你有多个相互依赖的分支时,rebase 一个分支会导致其他分支的引用过期。--update-refs 会自动更新所有受影响的分支引用:

bash
git rebase --update-refs main
默认启用 update-refs(Git 2.38+)
bash
git config --global rebase.updateRefs true

rebase 后强制推送

rebase 改变了提交的 SHA,推送到远程需要强制推送:

bash
# 推荐:使用 --force-with-lease(安全的强制推送)
git push --force-with-lease origin feature

# 不推荐:使用 --force(可能覆盖他人的提交)
git push --force origin feature
--force vs --force-with-lease
  • --force:无条件覆盖远程分支,即使远程有其他人推送的新提交
  • --force-with-lease:只在远程分支没有新提交时才推送,否则被拒绝

始终使用 --force-with-lease,避免覆盖他人的工作。

常见工作流

工作流 1:Feature 分支同步主分支

bash
# 每天开始开发前同步 main 的最新代码
git checkout feature
git fetch origin
git rebase origin/main

# 如果有冲突,解决后继续
git add .
git rebase --continue

# 推送到远程(feature 是个人分支,可以 force push)
git push --force-with-lease origin feature

工作流 2:提交前整理历史

bash
# 开发完成,准备合并前整理提交
git rebase -i main

# 在编辑器中:
# - squash 修复提交到功能提交中
# - reword 不清晰的提交信息
# - drop 不需要的调试提交
# - 调整提交顺序使逻辑更清晰

# 整理后推送
git push --force-with-lease origin feature

# 然后创建 PR / MR

工作流 3:pull --rebase 避免无意义的合并提交

bash
# 正常 git pull 可能产生合并提交
git pull origin main
# Merge branch 'main' of ... into main  ← 无意义的合并提交

# 使用 --rebase 保持线性历史
git pull --rebase origin main
# 本地提交被移到远程新提交之后,不产生合并提交

工作流 4:使用 fixup 快速修复历史提交

bash
# 1. 发现之前某个提交有 bug
git log --oneline
# abc1234 feat: 用户登录
# def5678 feat: 注册页面
# ghi9012 初始化

# 2. 修复 bug 并创建 fixup 提交
git add src/auth.ts
git commit --fixup abc1234

# 3. rebase 时自动合并
git rebase -i --autosquash ghi9012
# fixup 提交自动排列到 abc1234 下方并标记为 fixup

实际项目中的 rebase 场景

场景 1:PR/MR 提交前的历史整理

在创建 Pull Request 之前,整理提交历史是专业开发者的标准实践:

bash
# 开发过程中的提交(很乱)
git log --oneline
# f1a2b3c fix: 又修了一个 typo
# d4e5f6a fix: 修复 typo
# a1b2c3d WIP: 试试另一个方案
# 7e8f9a0 WIP: 调试中
# 1a2b3c4 feat: 用户认证模块
# 9d8e7f6 (main) ...

# PR 前整理(合并 WIP、修复到功能提交中)
git rebase -i main

编辑器中:

pick 1a2b3c4 feat: 用户认证模块
fixup 7e8f9a0 WIP: 调试中
fixup a1b2c3d WIP: 试试另一个方案
fixup d4e5f6a fix: 修复 typo
fixup f1a2b3c fix: 又修了一个 typo
bash
# 整理后的结果
git log --oneline
# abc1234 feat: 用户认证模块    ← 一个干净的提交
# 9d8e7f6 (main) ...

# 推送并创建 PR
git push --force-with-lease origin feature
理想的提交粒度

每个提交应该是一个逻辑完整的变更单元

  • feat: 添加用户认证模块(包含模型、API、测试)
  • fix: 修复登录时 token 过期问题
  • WIPfix typodebug试试看
  • ❌ 一个巨大的提交包含所有修改(应拆分为多个逻辑提交)

场景 2:Code Review 后的修改

PR 审查后需要修改代码,有两种策略:

bash
# 策略 1:追加新提交后 squash(推荐新手)
# 审查意见:修改变量命名、添加错误处理
git add .
git commit -m "review: 按审查意见修改"
# 然后 squash 到原始提交
git rebase -i main
# 将 review 提交 fixup 到对应的功能提交

# 策略 2:使用 fixup 自动关联(推荐进阶用户)
git add src/auth.ts
git commit --fixup abc1234   # abc1234 是需要修改的提交
# push 后,合并 PR 时选择 squash merge
# 或手动 rebase -i --autosquash

场景 3:Stacked PRs(分层 PR)

大型功能拆分为多个依赖的 PR,使用 rebase 维护依赖关系:

bash
# 结构:main → feature-base → feature-api → feature-ui

# 当 feature-base 合入 main 后,需要 rebase 后续分支
git checkout feature-api
git rebase main                    # feature-api 现在基于最新的 main

git checkout feature-ui
git rebase feature-api             # feature-ui 基于更新后的 feature-api

# 使用 --update-refs 自动处理(Git 2.38+)
git checkout feature-ui
git rebase --update-refs main
# 自动更新 feature-api 和 feature-ui 的引用

场景 4:清理 merge commit 保持线性历史

团队使用 merge 策略但想保持主分支线性历史:

bash
# main 分支有很多合并提交,想清理
# ❌ 不要对公共分支做这个!

# ✅ 正确做法:对自己的 feature 分支使用 rebase 替代 merge
# 而不是事后清理 main

# 设置团队规范:feature 分支合入 main 时使用 squash merge
# GitHub PR 设置 → 只允许 "Squash and merge"
# GitLab MR 设置 → 只允许 "Squash commits"

场景 5:处理长期分支的同步

长期维护的 feature 分支如何高效同步主分支的更新:

bash
# ❌ 错误做法:每次都 merge main 到 feature
git checkout feature
git merge main
# 结果:feature 的历史中充满了 merge commit

# ✅ 正确做法:定期 rebase
git checkout feature
git fetch origin
git rebase origin/main

# ✅ 最佳实践:每天早上第一件事
git fetch origin
git rebase origin/main
# 及时解决小冲突,而不是积累到最后变成大冲突
同步频率建议
主分支活跃度建议同步频率方式
每天 5+ 个合并每天rebase
每天 1-2 个合并每 2-3 天rebase
每周几个合并每周rebasemerge
主分支几乎不变合并前rebase

场景 6:迁移提交到新的基础分支

项目从 master 迁移到 main,或者需要将开发中的功能从一个发布分支移到另一个:

bash
# 场景:你的 feature 基于 release/v2.0,但现在要移到 release/v3.0
git rebase --onto release/v3.0 release/v2.0 feature

# 场景:master 重命名为 main 后,更新所有 feature 分支
git checkout feature
git rebase --onto main master

场景 7:修改历史中的作者信息

在交互式 rebase 中修改作者信息(常见于使用了错误的 Git 配置时):

bash
# 修改最近 5 个提交的作者
git rebase -i HEAD~5
# 将需要修改的提交标记为 edit

# rebase 暂停时修改作者
git commit --amend --author="正确的名字 <correct@email.com>"
git rebase --continue
# 对每个 edit 的提交重复上述操作

实用技巧

技巧 1:使用 --autostash 自动保存未提交修改

bash
# rebase 前如果有未提交的修改,会被拒绝
# 传统做法:手动 stash → rebase → stash pop
git stash
git rebase origin/main
git stash pop

# 更好的做法:使用 --autostash
git rebase --autostash origin/main
# Git 自动 stash → rebase → stash pop

# 设为默认行为
git config --global rebase.autoStash true

技巧 2:--committer-date-is-author-date 保留原始时间

rebase 后提交的 committer date 会变成当前时间。如果你想保留原始的提交时间:

bash
git rebase --committer-date-is-author-date main

技巧 3:交互式 rebase 中的批量操作

bash
# 将所有 pick 改为 squash(保留第一个)
# 在编辑器中,可以使用搜索替换:
# 查找:pick
# 替换:squash(或 fixup)
# 但要保留第一行的 pick!

# 或者使用命令行一步完成 squash
git reset --soft main
git commit -m "feat: 合并所有提交为一个"
# 这比 rebase -i 然后逐个标记 squash 快得多

技巧 4:配置推荐的 Git alias

bash
# 在 ~/.gitconfig 中添加
[alias]
    # 交互式 rebase(最常用)
    ri = rebase -i
    # rebase 到 origin/main
    rom = "!git fetch origin && git rebase origin/main"
    # 继续 rebase
    rc = rebase --continue
    # 放弃 rebase
    ra = rebase --abort
    # 整理最近 N 个提交
    fixup = "!f() { git rebase -i HEAD~$1; }; f"
    # 快速 fixup 提交
    cf = commit --fixup

# 使用
git ri main            # 交互式 rebase 到 main
git rom                # 同步远程 main
git rc                 # 解决冲突后继续
git fixup 5            # 整理最近 5 个提交
git cf abc1234         # 创建 fixup 提交

技巧 5:使用 exec 确保每个提交可构建

bash
# 在 rebase 过程中,对每个提交运行测试
git rebase -i main --exec "npm test"

# 或对每个提交运行 lint + test
git rebase -i main --exec "npm run lint && npm test"

# 如果某个提交导致测试失败,rebase 会暂停
# 你可以修复后 git rebase --continue
为什么要确保每个提交可构建?
  • git bisect 需要每个提交都能编译运行才能正确定位 bug
  • 代码审查者可能逐个提交查看
  • CI/CD 系统可能在任意提交上运行

技巧 6:团队 rebase 规范模板

markdown
## Git Rebase 团队规范

### 允许 rebase 的情况

- 自己的 feature 分支(未与他人共享)
- PR 合并前整理提交历史
- 同步主分支更新到 feature 分支

### 禁止 rebase 的情况

- main / develop 等公共分支
- 已创建 PR 且有他人基于此分支工作
- release 分支(发布后)

### PR 提交规范

- 每个 PR 最多 5-10 个有意义的提交
- 不允许 WIP、fixup、debug 等临时提交出现在最终 PR 中
- 使用 `git rebase -i` 整理后再提交 PR
- PR 合并方式:Squash and merge(小 PR)或 Merge commit(大 PR)

常见陷阱

陷阱 1:对公共分支 rebase 导致团队混乱
bash
# ❌ 千万不要这样做
git checkout main
git rebase feature    # 把 main rebase 到 feature 上
git push --force      # 强制推送 main

# 后果:所有人的 main 都与远程不一致
# 所有人都要执行:
git fetch origin
git reset --hard origin/main

记住:只 rebase 自己的分支,永远不要 rebase 公共分支

陷阱 2:rebase 方向搞反
bash
# ✅ 正确:将 feature rebase 到 main 上
git checkout feature
git rebase main
# feature 的提交移到 main 最新提交之后

# ❌ 错误:将 main rebase 到 feature 上
git checkout main
git rebase feature
# main 的提交被改写!

口诀:「站在 feature 上,rebase 到 main」

陷阱 3:rebase 后忘记 force push
bash
git rebase -i main
git push origin feature
# error: failed to push, non-fast-forward

# 因为 rebase 改变了 SHA,需要 force push
git push --force-with-lease origin feature
陷阱 4:交互式 rebase 中删除所有提交

如果在编辑器中删除了所有行(或全部标记为 drop),rebase 会导致分支回退到基础提交,丢失所有修改

补救方法:git refloggit reset --hard <rebase 前的 SHA>

陷阱 5:在 rebase 冲突中使用 git commit
bash
# 解决冲突后
git add .
git commit -m "resolve conflict"   # ❌ 错误!会创建新的提交

git add .
git rebase --continue              # ✅ 正确!继续 rebase 流程
陷阱 6:rebase 包含二进制文件的提交

二进制文件(图片、PDF 等)的冲突无法自动合并,每个涉及二进制文件的提交都可能需要手动处理。如果你的分支有大量二进制文件变更,考虑使用 merge 替代 rebase

常见问题

rebase 和 merge 该选哪个?

没有绝对的对错,取决于团队偏好和具体场景:

场景推荐方式
将 feature 合入 mainmerge
feature 分支同步 main 的更新rebase
整理本地提交历史rebase -i
多人协作的公共分支merge
个人的 feature 分支rebase
想保留完整的分支合并记录merge
想要干净的线性历史rebase
rebase 后怎么撤销?

使用 ORIG_HEADreflog

bash
# 方式 1:刚刚 rebase 完
git reset --hard ORIG_HEAD

# 方式 2:通过 reflog
git reflog
# 找到 rebase 前的 SHA
git reset --hard <sha>

详见 Git reset

rebase 时每个提交都要解决冲突,太烦了?

几个建议:

  1. 启用 rereregit config --global rerere.enabled true,Git 会记住冲突解决方案
  2. 频繁 rebase:不要积累太多差异
  3. 先 squash 再 rebase:减少需要逐个处理冲突的提交数量
    bash
    git rebase -i HEAD~10   # 先合并提交
    git rebase main          # 再同步主分支
git rebase -i 的编辑器看不懂 / 不会用?

编辑器中的每一行格式是 <命令> <SHA> <提交信息>。你只需要修改行首的命令关键字:

  • 保持不变 → pick
  • 修改提交信息 → reword
  • 合并到前一个 → squashfixup
  • 删除 → drop 或直接删除那一行
  • 重排序 → 移动整行的位置

保存并关闭编辑器后 Git 开始执行。如果搞砸了:git rebase --abort

能否 rebase 到不相关的分支上?

可以,使用 --onto

bash
git rebase --onto target-branch source-branch feature-branch

但这通常会导致大量冲突,因为两个分支的代码差异很大。

为什么有人说「不要 rebase 公共分支」?

因为 rebase 会改变提交的 SHA。如果其他人基于旧的 SHA 做了工作(pull、branch、cherry-pick),rebase 后这些 SHA 就不存在了,导致:

  • 其他人无法正常 pull(新旧历史冲突)
  • cherry-pick 的引用失效
  • CI/CD 中引用特定 SHA 的配置失效

所以规则是:只 rebase 自己的本地/个人分支,不要 rebase 多人共享的分支。

在 Windows PowerShell 中 rebase 编辑器打不开?

确保 Git 配置了编辑器:

powershell
# 使用 VS Code
git config --global core.editor "code --wait"

# 使用 Notepad++
git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"

# 使用 vim(Git Bash 默认)
git config --global core.editor vim

速查表

基础操作

目标命令
变基到 maingit rebase main
同步远程主分支git fetch && git rebase origin/main
pull 时使用 rebasegit pull --rebase origin main
取消 rebasegit rebase --abort
冲突解决后继续git rebase --continue
跳过当前提交git rebase --skip
撤销已完成的 rebasegit reset --hard ORIG_HEAD

交互式操作

目标命令
编辑最近 N 个提交git rebase -i HEAD~N
合并提交(squash)编辑器中将 pick 改为 squashfixup
修改提交信息编辑器中将 pick 改为 reword
编辑提交内容编辑器中将 pick 改为 edit
删除提交编辑器中将 pick 改为 drop 或删除该行
重排序提交编辑器中移动行的位置
自动整理 fixup 提交git rebase -i --autosquash

高级操作

目标命令
移动到其他基础git rebase --onto <newbase> <upstream>
保留合并历史git rebase --rebase-merges
自动更新分支引用git rebase --update-refs
推送 rebase 后的分支git push --force-with-lease origin <branch>
创建 fixup 提交git commit --fixup <sha>
启用 rereregit config --global rerere.enabled true
默认 pull 使用 rebasegit config --global pull.rebase true
默认启用 autosquashgit config --global rebase.autoSquash true

决策流程图

相关命令

  • git reset — 重置 HEAD 和分支引用,可用于撤销 rebase
  • git revert — 通过反向提交撤销修改(不改写历史)
  • git stash — 临时保存修改,常在 rebase 前使用
  • git filter-repo — 批量重写仓库历史(更大规模的历史改写)
  • git cherry-pick — 将指定提交应用到当前分支(rebase 的单提交版本)
  • git merge — 合并分支(rebase 的替代方案)
  • git config — pull.rebase、rebase.autoSquash 等配置

参考资料