讲解

git rebase 是另一种整合分支的方式,目标是让历史保持一条直线。场景:你从 main 岔出 feature 开发,期间 main 有了新提交,两条线分叉了。merge 会生成一个合并提交,历史里留下一个「叉」;rebase 则把 feature 上的提交摘下来,逐个「重放」到 main 的最新提交之后——就像你是从最新的 main 才开始开发的一样。git switch feature 然后 git rebase main,完成后 feature 线性接在 main 后面,main 再 merge feature 就是干净的快进。

rebase 的代价是「改写历史」:重放产生的提交内容相同但哈希不同,是全新的提交。由此引出 Git 最重要的协作铁律:永远不要 rebase 已经推送出去的提交。本地还没推的提交随便 rebase;一旦推送过,别人可能已经基于旧提交工作,你这边哈希全变了,他们 pull 时会得到重复、纠缠的历史。rebase 之后如果确实需要推送(个人功能分支上很常见),用 git push --force-with-lease。

git rebase -i(交互式变基)是整理本地提交的神器:git rebase -i HEAD~3 打开编辑器列出最近 3 个提交,把行首的 pick 改成 reword(改信息)、squash(合并进前一个)、drop(删除)或调整顺序,保存后 Git 按你的剧本重写历史。合并前把「wip」「fix typo」这类零碎提交整理成几个语义清晰的提交,是对评审者的尊重。rebase 过程中遇到冲突会暂停,解决后 git add 再 git rebase --continue,想放弃用 git rebase --abort。

示例

制造分叉,然后把 feature 变基到 main 上:

git switch -c feature
echo "功能 A" > a.txt
git add a.txt
git commit -qm "feat: 功能 A"
echo "功能 B" > b.txt
git add b.txt
git commit -qm "feat: 功能 B"
git switch main
echo "main 的进展" > progress.txt
git add progress.txt
git commit -qm "feat: main 的进展"
git switch feature
git rebase main
git log --oneline --graph --all
git switch main
git merge feature --no-edit
git log --oneline

变基后 feature 线性地接在 main 的最新提交之后,main 合并 feature 成为一次快进——最终历史是一条干净的直线。交互式变基需要编辑器交互,仅示意:

# 仅示意:交互式变基会打开编辑器,整理最近 3 个提交
git rebase -i HEAD~3
# 把行首 pick 改成 reword / squash / drop,保存退出后 Git 按剧本重写

常见坑

  • rebase 已推送的提交:铁律中的铁律。公共分支(main、共享的 release)绝不 rebase;个人分支 rebase 后推送用 --force-with-lease。
  • rebase 冲突时手足无措:rebase 是逐个重放提交,可能冲突多次,每次解决后 add + rebase --continue。状态随时可用 git status 查看,--abort 随时全身而退。
  • 以为 rebase 后内容丢提交:rebase 只搬动提交不改内容(除非有冲突),提交数和改动总量不变,变的是哈希和父提交。
  • 在共享分支上 pull --rebase 成习惯:pull --rebase 只影响你本地未推送的提交是安全的;一旦它改写了已推送的提交,下一次 push 就需要强推,连锁反应开始了。

小结

rebase 把分支提交重放到目标分支之后,得到线性历史;代价是改写哈希,所以只对未推送的提交使用。-i 交互式整理提交,--continue/--abort 处理冲突与退出。下一章学一个救场工具:stash。