08. rebase 不是 merge 的替代品:Git 故事线重构进阶

「Git」系列已发布: 00. 改崩代码不敢回退?Git 版本控制 3 分钟救你狗命 | 01. Git 装完不会配?Windows/macOS/Linux 三端配置一次到位 | 02. Git 配置总踩坑?全局/仓库/SSH 密钥一次搞懂 | 03. add/commit/push 别再死记:Git 工作流核心概念实操 | 04. Git 分支管理:5 步彻底搞懂 branch 与 merge | 05. clone/fetch/pull/push 分不清?Git 远程协作实战 | 06. 给版本打上永久印记:Git 标签管理与发布实战 | 07. 切分支怕丢改动?Git stash 暂存恢复保护现场 | 08. rebase 不是 merge 的替代品:Git 故事线重构进阶(本文) | 09. Git 日志与调试:log/blame/diff 让历史无所遁形

rebase 常被误用为 merge 的平替,其实它是“重构提交历史”的手术刀。本文讲清底层原理与适用边界,用对地方历史才干净。

分支管理(第 04 篇)和基础变基操作要很熟。下面涉及的交互式变基和历史重写都是破坏性操作,只在个人 feature 分支上练,千万别在共享分支上玩。

一、变基底层干了什么

搞清楚底层机制能避免大部分坑。git rebase分三步走:

  1. 找当前分支和目标分支的共同祖先。
  2. 把当前分支上每个提交的 diff 暂存起来。
  3. 切到目标分支最新提交,逐一 apply 这些 diff,生成全新提交。

变基前,feature 从 main 的 D 点分叉,拥有 A、B、C 三个提交:

gitGraph commit id: "D" branch feature commit id: "A" commit id: "B" commit id: "C" checkout main commit id: "E" commit id: "F" commit id: "G"

执行 git rebase main 分三步:① 找到共同祖先;② 暂存 A、B、C 的 diff;③ 在 G 上依次 apply,生成全新的 A’、B’、C’:

gitGraph commit id: "D" commit id: "E" commit id: "F" commit id: "G" branch feature commit id: "A'" commit id: "B'" commit id: "C'"

注意:A’、B’、C’ 是全新的提交,哈希和 A、B、C 完全不同。这就是为什么变基后本地和远程分支会分叉——历史已经被重写了。

1.1 交互式变基深入

1.1.1 合并提交(squash / fixup)

最实用的场景:把开发中零散的提交合并成清晰的逻辑单元。


# 变基最近 5 次提交

git rebase -i HEAD~5

编辑器里会看到:

a1b2c3d 初步实现登录功能
pick b2c3d4e 修复登录页面样式

pick d4e5f6g 修复校验逻辑 bug
pick e5f6g7h 添加单元测试

把要合并的改成
squash或fixup:

a1b2c3d 初步实现登录功能
squash b2c3d4e 修复登录页面样式

squash d4e5f6g 修复校验逻辑 bug
pick e5f6g7h 添加单元测试

结果:5 个提交 → 2 个提交(“实现登录功能” + “添加单元测试”)。squash和fixup的区别:squash允许你编辑合并后的提交信息,fixup直接把被合并提交的信息丢掉。

1.2 拆分提交(edit)

一个大提交拆成多个小的:

a1b2c3d 实现用户模块
edit b2c3d4e 实现订单模块

到
b2c3d4e时会暂停:


# 把提交回退到暂存区

git reset HEAD~1

# 分文件提交

git add src/order/create.py
git commit -m "实现订单创建功能"
git add src/order/list.py
git commit -m "实现订单列表功能"

# 继续

git rebase --continue

1.2.1 调顺序

在编辑器里直接拖动行就行:

# 原始顺序
pick a1b2c3d 添加单元测试
pick b2c3d4e 实现核心功能

# 调整为合理顺序(先功能、再测试、最后文档)
pick b2c3d4e 实现核心功能
pick a1b2c3d 添加单元测试

1.2.2 删提交(drop)

开发中不小心提交了调试代码或临时文件:

a1b2c3d 实现功能 A
drop b2c3d4e 临时调试代码——勿合并  # 直接删掉

1.3 变基冲突


# 变基时碰上冲突

git rebase main

# CONFLICT (content): Merge conflict in src/utils.py

# 解决后

git add src/utils.py
git rebase --continue

# 跳过当前提交(放弃它的修改)

git rebase --skip

# 完全放弃变基

git rebase --abort

变基冲突和
merge 冲突有一个关键区别:变基是逐提交应用的,同一个文件可能在不同提交里反复冲突。要有耐心,一次一次来。

1.4 高级变基

1.4.1 --onto:移植一段提交

把 feature 分支中某一段提交搬到 main 上:

git rebase --onto main E feature

场景:feature 从 develop 分叉,但想直接把 feature 中新增的提交变基到 main。

%% 变基前 gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch develop checkout develop commit id: "E" commit id: "F" commit id: "G" branch feature checkout feature commit id: "H" commit id: "I"

执行 git rebase --onto main G feature 后:

%% 变基后:feature 的 H、I 被重新落到 main 之上 gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch feature checkout feature commit id: "H'" commit id: "I'" checkout main merge feature branch develop checkout develop commit id: "E" commit id: "F" commit id: "G"

1.4.2 保留合并提交

默认git rebase会丢弃合并提交、把历史线性化。如果想保留某些合并提交:

git rebase --rebase-merges main

这在保留
CI 通过的合并提交(作为构建验证节点)时很有用。

1.5 autosquash

配合--fixup提交自动 squash:


# 先建 fixup 提交

git commit --fixup a1b2c3d -m "修复上次提交的小问题"

# 变基时自动应用

git rebase -i --autosquash HEAD~3

1.6 变基安全铁律

1.6.1 黄金法则

永远不要对已经推到公共仓库的提交变基。
怎么判断:


# 检查当前分支是否已推送

git status

# "Your branch is ahead of 'origin/feature' by 2 commits"

# 且确认远程没人基于你的分支工作 → 可以变基

#

# "Your branch and 'origin/main' have diverged"

# → 远程已有不同提交,变基会导致冲突和强制推送

# 看远程分支上多了哪些你本地没有的提交

git log origin/feature..feature

如果不小心对公共分支变基并
force push 了,通知所有团队成员执行:

git fetch origin
git rebase origin/main

# 或者更粗暴但更安全

git reset --hard origin/main

1.6.2 force-with-lease


# 别用这个

git push --force

# 用这个

git push --force-with-lease

# 更安全的:显式指定期望的远程状态

git push --force-with-lease=feature:origin/feature

1.7 文章引用

📌 本文首发于微信公众号 【运维知识点滴】——专注运维实战干货,微信搜索“运维知识点滴”或扫下方二维码关注,更新不迷路。
📎 微信原文:08. rebase 不是 merge 的替代品:Git 故事线重构进阶

微信公众号【运维知识点滴】 微信小程序【A5单据合并&大试卷拆分转A4打印】
运维实战干货 · 关注追更 Word 转 PDF · 试卷/发票打印神器 · 免费
运维实战干货 · 关注追更 Word 转 PDF · 试卷/发票打印神器 · 免费

💡 小程序【A5单据合并&大试卷拆分转A4打印】是干嘛的? 一个 Word 转 PDF 的打印神器,专治“文档版式和打印机对不上”:

  • A3 试卷打不出来? 学校发的电子版试卷多是 A3,家用打印机只吃 A4——上传 Word 一键转换:可缩到一页 A4(页数不变),也可对半拆成两张 A4(1:1 原大、字更清晰),两种模式自选;
  • 版式不乱:真实渲染引擎原样转换、绝不重排内容,转出的 PDF 和原 Word 排版一致,公式/表格/图片不跑版;
  • 两张 A5 单据拼一张 A4:出租车票、火车票等报销凭证拼版后,一次打印、整齐粘贴;
  • 隐私省心:无需注册,转换结果留存 5 天、最多下载 5 次即自动删除,不留任何历史记录;
  • 微信扫码即用,免费、免安装,支持 doc / docx(≤50MB)。

上一篇:07. 切分支怕丢改动?Git stash 暂存恢复保护现场 | 下一篇:09. Git 日志与调试:log/blame/diff 让历史无所遁形