git rebase
变基是两个 Git 实用程序之一,专门用于将变更从一个分支集成到另一个分支。另一个变更集成实用程序是 git merge。合并始终是向前移动的变更记录。或者,变基具有强大的历史记录重写功能。要详细了解合并与变基,请访问我们的合并与变基指南。变基本身有 2 种主要模式:“手动”模式和“交互”模式。我们将在下面更详细地介绍不同的变基模式。
什么是 git rebase?
变基是将一系列提交移动或合并到新的基本提交的流程。在功能分支工作流程的上下文中,变基最为有用且易于可视化。整个流程可以显示为以下内容:
从内容角度来看,变基是将分支的基础从一个提交变更为另一个提交,使它看起来好像您是从另一个提交中创建分支一样。在内部,Git 通过创建新的提交并将其应用到指定的基础来实现此目的。重要的是要明白,尽管分支看起来一样,但它是由全新的提交组成的。
用法
变基的主要原因是保持线性项目历史记录。例如,假设自您开始开发功能分支以来,主分支已经取得了进展。您想在功能分支中获取主分支的最新更新,但您想保持分支的历史记录干净,这样您就好像在研究最新的主分支一样。这为以后将您的功能分支干净地合并回主分支带来了好处。我们为什么要保持“干净的历史记录”?执行 Git 操作来调查回归的引入情况时,干净历史记录的好处显而易见。更真实的场景是:
1. 在主分支中发现了一个错误,曾经成功运行的功能现在已损坏。
2. 开发人员使用 git log 检查主分支的历史记录,由于是“干净的历史记录”,因此开发人员可以很快推断出项目的历史记录。
3. 开发人员无法使用 git log 识别错误是何时引入的,因此开发人员执行了 git bisect。
4. 由于 git 历史记录很干净,因此 git bisect 有一组优化的提交用于在查找回归时进行比较。开发人员很快找到了引入 bug 的提交,并能够采取相应的行动。
在各自的使用页面上了解有关 git log 和 git bisect 的更多信息。
您可以通过两种方式将功能集成到主分支中:直接合并或变基然后合并。前一个选项导致三向合并和合并提交,而后者会导致快速合并和完全线性的历史记录。下图演示了基于主分支变基如何推动快进合并。
变基是将上游变更集成到本地存储库中的常用方法。每当您想查看项目的进展情况时,使用 Git 合并引入上游变更都会导致多余的合并提交。另一方面,变基就像是根据每个人已经做过的事情来进行变更。
不要变基公共历史记录
正如我们之前在重写历史记录中讨论过的那样,一旦提交被推送到公共存储库,您就不应该对提交进行变基。变基会将旧的提交替换为新的提交,看起来就像您的那部分项目历史记录突然消失了。
Git 标准变基与 Git 交互式变基
Git 交互式变基指的是 git rebase 接受 --i 参数。这代表“交互式”。在没有任何参数的情况下,该命令在标准模式下运行。在这两种情况下,我们都假设我们创建了一个单独的功能分支。
# Create a feature branch based off of main
git checkout -b feature_branch main
# Edit files
git commit -a -m "Adds new feature"标准模式下的 Git 变基会自动接收当前工作分支中的提交,并将其应用于传递分支的负责人。
git rebase <base>这会自动将当前分支变基为 <base>,可以是任何类型的提交引用(例如 ID、分支名称、标记或对 HEAD 的相对引用)。
运行带有 -i 标记的 git rebase 会开始交互式变基会话。交互式变基不是盲目地将所有提交移至新库,而是让您有机会在流程中修改单个提交。这使您可以通过删除、拆分和修改现有的一系列提交来清理历史记录。就像增强型 Git commit --amend 一样。
git rebase --interactive <base>这会将当前分支变基为 <base>,但会使用交互式变基会话。这将打开一个编辑器,您可以在其中为每个要变基的提交输入命令(如下所述)。这些命令决定如何将单个提交转移到新库。您也可以对提交列表进行重新排序,以变更提交本身的顺序。为变基中的每个提交指定命令后,Git 将开始使用变基命令回放提交。变基编辑命令如下所示:
pick 2231360 some old commit
pick ee2adc2 Adds new feature
# Rebase 2cf755d..ee2adc2 onto 2cf755d (9 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit其他变基命令
正如重写历史记录页面中详细介绍的那样,变基可以用来变更较旧的提交和多个提交、已提交的文件和多条消息。虽然这些是最常见的应用,但 git rebase 还有其他命令选项,这些选项在更复杂的应用中可能很有用。
git rebase -- d意味着在回放过程中,该提交将从最终合并的提交块中丢弃。git rebase -- p会保留提交的原始状态。它不会修改提交的消息或内容,并且仍然是分支历史记录中的独立提交。git rebase -- x会在回放过程中,对每个标记的提交执行命令行 shell 脚本。一个有用的例子是在特定提交上运行代码库的测试套件,这有助于在变基过程中定位回归问题。
回顾
交互式变基使您可以完全控制项目历史记录的样子。这为开发人员提供了很大的自由,因为它允许他们在专注于编写代码的同时提交一份“混乱的”历史记录,然后事后回去清理一下。
大多数开发人员喜欢在将功能分支合并到主存储库之前使用交互式变基来完善功能分支。这使他们有机会压缩无关紧要的提交,删除过时的提交,并确保其他所有内容都井井有条,然后再提交到“官方”项目历史记录。对其他人来说,整个功能看起来就像是在一系列精心策划的提交中开发的。
交互式变基的真正力量可以从由此产生的主分支的历史记录中看出。对其他人来说,看来您是一位出色的开发人员,第一次实现了这个新功能,提交量恰到好处。这就是交互式变基可以保持项目历史记录干净且有意义的方式。
配置选项
有一些变基属性可以使用 git config 进行设置。这些选项将改变 git rebase 输出的外观和感觉。
rebase.stat:一个布尔值,默认设置为 false。该选项用于切换可视化差异统计内容的显示,这些内容会展示自上次变基以来发生的变更。rebase.autoSquash:一个切换--autosquash行为的布尔值。rebase.missingCommitsCheck:可设置为多个值,这些值会改变变基过程中针对缺失提交的处理行为。
| 在交互模式下打印警告输出,警告已删除的提交 |
| 停止变基并打印已删除的提交警告消息 |
| 默认情况下,此设置会忽略任何缺失的提交警告 |
rebase.instructionFormat:一个git log格式字符串,将用于格式化交互式变基显示
高级变基应用
可以向 git rebase 命令传入命令行参数 --onto。在 git rebase --onto 模式下,命令会扩展为:
git rebase --onto <newbase> <oldbase>--onto 命令支持更强大的形式或变基,允许传递特定的引用作为变基的提示。假设我们有一个示例代码存储库,其分支结构如下:
o---o---o---o---o main
\
o---o---o---o---o featureA
\
o---o---o featureBfeatureB 基于 featureA,但是,我们意识到 featureB 不依赖于 featureA 中的任何变更,只能从主版本中分支。
git rebase --onto main featureA featureBfeatureA 是 <oldbase>。main 变成 <newbase> 而 featureB 是 <newbase>HEAD 将要指出的内容的参考。那么结果是:
o---o---o featureB
/
o---o---o---o---o main
\
o---o---o---o---o featureA了解变基的危险
使用 Git 变基时需要考虑的一个注意事项是,在变基工作流程中,合并冲突可能会变得更加频繁。如果您有一个长期分支偏离了主分支,就会发生这种情况。最终,您会想对主分支进行变基,那时它可能包含许多新提交,您的分支变更可能会与这些提交发生冲突。这很容易解决,方法是频繁地根据主分支变基分支,并更频繁地提交。处理冲突时,可以将 --continue 和 --abort 命令行参数传递给 git rebase,以推进或重置变基。
更严重的变基警告是交互式历史记录重写丢失的提交。在交互模式下运行 rebase 并执行 squash 或 drop 等子命令将从分支的即时日志中删除提交。乍一看,这看起来好像提交已经永久消失了。使用 git reflog,这些提交可以还原,整个变基也可以撤销。有关使用 git reflog 查找丢失提交的更多信息,请访问我们的 Git 引用日志文档页面。
Git 变基本身并不是很危险。真正的危险情况发生在执行历史记录重写交互式变基并将结果强制推送到其他用户共享的远程分支时。这种模式应该避免,因为它能够在其他远程用户拉取时覆盖其他远程用户的工作。
从上游变基中恢复
如果其他用户进行了变基并强制推送到您要提交的分支,则 git pull 会使用强制推送的提示覆盖您基于先前分支的任何提交。幸运的是,使用 git reflog 您可以获得远程分支的引用日志。在远程分支的引用日志上,您可以在它变基之前找到一个引用。然后,您可以使用 --onto 选项根据该远程引用对分支进行变基,如上文“高级变基应用”部分所述。
摘要
在这篇文章中,我们介绍了 git rebase 的用法。我们讨论了基本和高级用例以及更高级的示例,一些关键的讨论要点包括:
git rebase 标准模式与交互模式
git rebase 配置选项
git rebase --onto
git rebase 丢失的提交
我们研究了 git rebase 的使用情况,使用的其他工具包括 git reflog、git fetch 和 git push 等。访问他们的相应页面以获取更多信息。