Rebase — 是Git中的一种操作,它将一系列提交移动到一个新的基础提交上,重写分支历史。与Merge不同,Rebase不创建合并提交,而是将提交重新应用到目标分支的当前状态之上。根据git-scm.com, 2026的数据,58%的Git项目使用rebase来保持清晰的线性提交历史。
要点
Rebase(变基)— 是一种Git操作,它将当前分支的提交移动到一个新的参考点(基础)上。与创建合并提交不同,rebase从源分支中取出每个提交,并依次将其应用到新基础之上。结果是产生没有分支的线性提交序列。
Rebase这个名称来自“re-base”——改变基础。如果说merge是在一个点上合并两个分支,那么rebase实际上是将整个分支移动到一个新位置,造成一种从目标分支当前状态开始开发的错觉。这创造了完美顺序工作的假象。
根据Atlassian, 2025的数据,使用rebase处理功能分支的团队比仅使用merge的团队在分析提交历史上少花费30%的时间。线性历史简化了git blame、bisect和通过git log --oneline查看日志。
Merge通过创建一个具有两个父级的提交来合并分支。Rebase重写历史:新提交用新的哈希值重新创建,尽管其中的更改与原始提交相同。这意味着rebase会更改提交的SHA标识符,这对公共分支至关重要。
Rebase的机制包括四个步骤:Git确定当前分支和目标分支的共同祖先(合并基础),然后将当前分支的每个提交依次应用到目标分支之上。如果在某一步出现冲突——rebase将停止并等待解决。
# 初始状态:功能分支落后develop 3个提交
git checkout feature/new-login
git rebase develop
# Git从功能分支获取3个提交并将其应用到develop上
# 如果没有冲突——rebase自动完成
# 如果有——Git在冲突的提交处停止
在rebase之后,功能分支包含develop中的所有提交以及自己的提交,这些提交看起来像是develop的延续。这允许通过fast-forward合并到develop中,而无需创建合并提交。
让我们看一个详细的例子:一个开发人员从develop创建了一个功能分支,提交了两个提交,与此同时其他开发人员向develop添加了三个提交。Rebase将功能分支的两个提交移动到一个新位置,创建具有新SHA的副本。
# 1. 创建功能分支
git checkout -b feature/payment-refactor develop
# 2. 在功能分支中提交
git commit -m "refactor: extract payment validation"
git commit -m "refactor: add payment gateway interface"
# 3. 更新develop(同事的工作)
git checkout develop
git pull
# 4. 将功能分支变基到新的develop上
git checkout feature/payment-refactor
git rebase develop
# 5. 现在功能分支可以通过fast-forward合并
git checkout develop
git merge feature/payment-refactor
如果在第4步出现冲突,Git将在有问题的提交处停止。开发人员解决冲突,执行git add并运行git rebase --continue。如果需要跳过提交——git rebase --skip,如果取消整个rebase——git rebase --abort。
--empty标志控制rebase在空提交时的行为——当提交的所有更改已经存在于目标分支中的情况。默认情况下,rebase会停止并要求做出决定。使用--empty=drop标志,Git会自动跳过这些提交而不会停止,这加快了大量提交的批量变基。
Interactive rebase(git rebase -i)—— 是一个强大的编辑提交历史的工具。它打开一个编辑器,显示提交列表和关键命令:pick(保留)、reword(更改消息)、edit(更改内容)、squash(与上一个合并)、fixup(合并而不带消息)、drop(删除)。
# 最后4个提交的交互式rebase
git rebase -i HEAD~4
# 在编辑器中将打开rebase计划:
# pick a1b2c3 feat: add login screen
# pick d4e5f6 fix: login validation
# pick g7h8i9 fix: login layout
# pick j0k1l2 docs: add login comments
# 我们改为:
# pick a1b2c3 feat: add login screen
# squash d4e5f6 fix: login validation
# squash g7h8i9 fix: login layout
# drop j0k1l2 docs: add login comments
结果:三个提交(登录屏幕、验证、布局)被压缩为一个,包含注释的提交被删除。这允许为代码审查提交没有草稿和修正的干净历史。Interactive rebase是在Pull Request之前准备功能分支的标准工具。
Rebase和Merge解决相同的任务——集成更改——但采用根本不同的方式。两者之间的选择取决于您希望在git log中看到什么样的历史记录以及还有谁在与您的分支一起工作。
| 标准 | Merge | Rebase |
|---|---|---|
| 历史 | 保留分支 | 线性,无分支 |
| 合并提交 | 创建(除ff外) | 不创建 |
| 提交SHA | 不更改 | 创建新的 |
| 安全性 | 对公共分支安全 | 危险——重写历史 |
| 日志可读性 | 分支图 | 直线 |
| git bisect | 方便——可见合并点 | 方便——线性序列 |
实践规则:使用merge集成到公共分支(develop、main),使用rebase将个人功能分支更新到最新状态。许多团队组合使用:将功能分支rebase到develop,然后使用--no-ff merge合并到develop。
Git bisect—— 用于查找引入回归的提交的工具。使用merge时,git bisect正确通过合并提交,考虑两个父级。使用rebase时,bisect运行更快,因为历史是线性的,不需要分支。但是,如果在提交为团队所知之后才进行rebase,原始SHA将丢失,bisect可能无法找到有问题的提交。
Rebase在三种场景下是最优的:准备功能分支进行Pull Request、将个人分支更新到main/develop的最新状态、以及在合并前清理历史。在每种情况下,rebase都能在不给团队工作带来风险的情况下提高历史的可读性。
在Pull Request之前,建议执行interactive rebase,将工作提交(WIP、审查后的修正)合并为有意义的逻辑单元。这简化了代码审查:审查者看到的不是15个小的提交,而是3-5个带有清晰消息的结构化更改。
对于更新功能分支,rebase比merge更可取,因为它不会创建不必要的合并提交。如果您在功能分支中定期执行git rebase develop,最终合并后将不会有10个合并提交的级联——只有干净的位于develop之上的功能提交。
通过interactive rebase在合并前清理历史可以隐藏小的修正(拼写错误、格式化),并根据功能对提交进行分组。Git消息应遵循Conventional Commits约定(fix:、feat:、refactor:、docs:),这将生成自动更新日志。
Rebase——如果使用不当,这是一个危险的操作。主要风险——重写已发布的历史。如果开发人员对其他人已经推送并正在使用的分支执行rebase,他们的本地副本将不同步,他们将不得不执行force-pull,存在数据丢失的风险。
为了最小化风险,请遵守规则:仅对未发布的个人分支执行rebase。如果分支已在共享仓库中——使用带有--no-ff的merge。如果需要对已发布的分支执行rebase——请通知团队并提前协调force push。
针对危险rebase的自动保护通过服务器端钩子实现:Git服务器端的pre-receive钩子可以检查push是否重写了已发布的提交。GitHub和GitLab为受保护的分支提供内置保护——除非管理员移除保护,否则force push将被阻止。
常见问题
分支的历史将改变——提交的SHA将变得不同。所有已经推送过这个分支或从中创建了派生分支的人在git pull时都会遇到冲突。恢复将需要手动干预,并可能导致提交丢失。
完成之前——git rebase --abort。完成之后——只能通过git reflog,如果rebase是最近做的。reflog保存HEAD的移动历史,通过它可以恢复到rebase之前的状态:git reset --hard HEAD@{1}。
Rebase将一系列提交移动到一个新的基础。Cherry-pick将一个或多个特定的提交应用到当前分支。Rebase对于整个链是自动的,cherry-pick——手动选择每个提交。
建议做,但不是必须的。PR前的rebase将分支更新到main/develop的最新状态并清理历史。如果分支是最近创建的并且不需要更新——使用interactive rebase清理提交就足够了。
标签在rebase时不会移动。如果被rebase的提交上有一个标签,这个标签将保留在旧提交上,该提交现在不属于分支历史。建议不要在功能分支中标记提交,只在main中标记。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。