Git Rebase 完全指南:从恐惧到精通
来源:https://www.brethorsting.com/blog/2026/01/git-rebase-for-the-terrified/
前言
作为 OneBusAway 项目的维护者,我经常要求贡献者在合并前对他们的分支进行 rebase。回应往往是犹豫甚至恐惧。我理解这种感受——rebase 在开发者社区中有着毁坏工作的恶名,网上的各种警告更加剧了这种恐惧。
但事实是:rebase 出错的最坏情况不过是删除本地克隆并重新开始。就这样。你的远程 fork 仍然存在,主仓库也还在。你总是可以恢复的。
既然消除了恐惧,让我来展示如何正确地使用 rebase。
为什么维护者要求 rebase
当你从 main 分支创建一个分支并工作几天后,main 分支仍在持续前进。其他 PR 被合并。当你的 PR 准备好时,你的分支历史已经与 main 产生了分歧。
虽然合并提交可以结合它们,但这会创建混乱的历史,提交交错在一起,使理解变更内容和原因变得更加困难。
Rebase 会将你的提交在当前的 main 分支上重放,就像你今天才创建这个分支一样。结果是清晰、线性的历史,更容易审查和 bisect(二分查找)以追踪 bug。

实际操作命令
第一步:配置上游仓库
首先,确保你已将上游仓库配置为 remote。如果你 fork 了一个仓库并克隆了你的 fork,你可能只有 origin 指向你的 fork:
git remote -v如果没有看到主仓库,添加它:
git remote add upstream https://github.com/OneBusAway/onebusaway-ios.git第二步:获取最新变更
从上游获取最新变更:
git fetch upstream第三步:切换到特性分支
确保你在你的特性分支上:
git checkout your-branch-name第四步:推送备份
在 rebase 之前,将当前工作推送到你的远程 fork。这为你提供了一个备份,以防出错时可以恢复:
git push origin your-branch-name第五步:执行 rebase
现在将你的分支 rebase 到上游的 main 分支:
git rebase upstream/main如果没有冲突,你就完成了 rebase。如果有冲突,Git 会停止并告诉你哪些文件需要处理。
理解冲突标记
当打开一个有冲突的文件时,你会看到类似这样的内容:
<<<<<<< HEAD
const timeout = 5000;
=======
const timeout = 10000;
>>>>>>> upstream/main这在理解之前很困惑,但每个部分的意思是:
<<<<<<< HEAD和=======之间的内容是你的代码,来自正在重放的提交=======和>>>>>>> upstream/main之间的内容是main 中的代码,与你的代码冲突
你的工作是决定最终代码应该是什么样的。有时你想要你的版本,有时是他们版本,有时是两者的结合。删除标记并只保留你想保留的代码。
推荐工具:我总是使用 VS Code 来完成这一步。它的合并冲突 UI 是我找到的最清晰的:它在每个冲突上方显示"接受当前更改"、"接受传入更改"、"接受两者更改"和"比较更改"按钮。你可以逐个点击冲突,无需手动查找标记。
当冲突变得棘手时
有些冲突是直接的:两个人以不同方式更改了同一行。选择一个或组合它们。
其他的则更困难。如果你在 rebase 多个提交,并且同一文件反复冲突,通常意味着你的更改以某种方式相互构建,无法干净地应用于新的基础。
处理策略
1. 先压缩,再 rebase
如果你有很多小提交,在 rebase 之前将它们合并成一两个逻辑提交。更少的提交意味着更少的冲突机会。
# 交互式 rebase 来压缩提交
git rebase -i HEAD~n # n 是要压缩的提交数2. 中止并尝试不同的方法
如果冲突太多,执行 git rebase --abort 并考虑你的分支是否分歧太远。有时从 main 创建新分支并手动重新应用你的更改会更容易。
git rebase --abort
git checkout main
git pull upstream main
git checkout -b new-branch-name
# 手动应用你的更改3. 使用 git rerere
如果你发现自己反复解决相同的冲突,使用以下命令启用 rerere(重用记录的解决方案):
git config --global rerere.enabled trueGit 会记住你如何解决冲突,并在下次自动应用相同的解决方案。
解决冲突后
解决每个文件的冲突后:
git add path/to/resolved/file
git rebase --continue重复直到 rebase 完成。如果出现问题并想要中止:
git rebase --abort这会将你的分支恢复到开始前的状态。

验证你的更改
rebase 后,验证你的更改仍然有效:
git log --oneline upstream/main..HEAD这只显示你领先于 main 的提交。确保它们看起来正确。然后构建项目并运行测试。rebase 有时会导致微妙的问题,如果上游更改与你的工作冲突,而合并没有捕获到这些问题。
Force Push
这是人们紧张的地方。rebase 后,你的本地分支已经与远程分支分歧。正常的 git push 会失败。你需要 force push:
git push --force-with-lease origin your-branch-name--force-with-lease 标志比 --force 更安全,因为如果有人在你上次获取后推送到你的分支,它会失败。这可以防止你意外覆盖其他人的工作。
重要:永远不要 force push 到 main 或任何共享分支。只对你自己的特性分支进行 force push。
当一切都出错时
如果你把事情搞砸了,无法弄清楚如何恢复,这里是"核选项":
- 将你想保存的任何工作推送到你的远程 fork(甚至到临时分支)
- 删除你的本地克隆
- 从你的 fork 重新克隆
- 再次添加上游 remote
- 重新开始 rebase 过程
这对我来说从未失败过。你的提交存在于 GitHub 上,直到你明确删除它们。你总是可以恢复。
重要注意事项
Rebase 会重写提交历史。这对于只有你工作的特性分支是没问题的。对于其他人基于其工作的分支,这不行。如果你在一个分支上与某人合作,在 rebase 之前协调,或者直接使用合并提交。
总结
一旦你理解了你总是可以恢复,rebase 就不再可怕了。最坏的情况是几分钟的重新克隆。好处是清晰的项目历史,更容易理解和维护。
核心要点:
- 在 rebase 之前推送备份
- 使用
--force-with-lease而不是--force - 永远不要 rebase 共享分支
- 理解冲突标记的含义
- 最坏情况:重新克隆,一切恢复
参考资料
- 原文:Git Rebase for the Terrified
- Git 官方文档:git-rebase
- VS Code 合并冲突文档:Resolve merge conflicts