什么是 git rebase?
变基是将一系列提交移动或合并到新的基本提交的流程。在功能分支工作流程的上下文中,变基最为有用且易于可视化。整个流程可以显示为以下内容:
从内容角度来看,变基是将分支的基础从一个提交变更为另一个提交,使它看起来好像您是从另一个提交中创建分支一样。在内部,Git 通过创建新的提交并将其应用到指定的基础来实现此目的。重要的是要明白,尽管分支看起来一样,但它是由全新的提交组成的。
相关资料
Git 速查表
查看解决方案
了解 Bitbucket Cloud 的 Git
使用
变基的主要原因是保持线性项目历史记录。例如,假设自您开始开发功能分支以来,主分支已经取得了进展。您想在功能分支中获取主分支的最新更新,但您想保持分支的历史记录干净,这样您就好像在研究最新的主分支一样。这为以后将您的功能分支干净地合并回主分支带来了好处。我们为什么要保持“干净的历史记录”?执行 Git 操作来调查回归的引入情况时,干净历史记录的好处显而易见。更真实的场景是:
1. 在主分支中发现了一个错误,曾经成功运行的功能现在已损坏。
2. A developer examines the history of the main branch using git log
because of the "clean history" the developer is quickly able to reason about the history of the project.
3. The developer can not identify when the bug was introduced using git log
so the developer executes a git bisect
.
4. Because the git history is clean, git bisect
has a refined set of commits to compare when looking for the regression. The developer quickly finds the commit that introduced the bug and is able to act accordingly.
在各自的使用页面上了解有关 git log 和 git bisect 的更多信息。
您可以通过两种方式将功能集成到主分支中:直接合并或变基然后合并。前一个选项导致三向合并和合并提交,而后者会导致快速合并和完全线性的历史记录。下图演示了基于主分支变基如何推动快进合并。
变基是将上游变更集成到本地存储库中的常用方法。每当您想查看项目的进展情况时,使用 Git 合并引入上游变更都会导致多余的合并提交。另一方面,变基就像是根据每个人已经做过的事情来进行变更。
不要变基公共历史记录
正如我们之前在重写历史记录中讨论过的那样,一旦提交被推送到公共存储库,您就不应该对提交进行变基。变基会将旧的提交替换为新的提交,看起来就像您的那部分项目历史记录突然消失了。
Git rebase standard vs git rebase interactive
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>
这会自动将当前分支变基为 HEAD
的相对引用)。
运行带有 -i
标记的 git rebase
会开始交互式变基会话。交互式变基不是盲目地将所有提交移至新库,而是让您有机会在流程中修改单个提交。这使您可以通过删除、拆分和修改现有的一系列提交来清理历史记录。就像增强型 Git commit --amend
一样。
git rebase --interactive <base>
这会将当前分支变基为
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.inctionFormat:
一个git log
格式字符串,将用于格式化交互式变基显示
高级变基应用
命令行参数 --onto
可以传递给 git rebase
。在 git rebase --onto
模式下,命令会扩展为:
git rebase --onto <newbase> <oldbase>
The --onto
command enables a more powerful form or rebase that allows passing specific refs to be the tips of a rebase. Let’s say we have an example repo with branches like:
o---o---o---o---o main
\
o---o---o---o---o featureA
\
o---o---o featureB
featureB 基于 featureA,但是,我们意识到 featureB 不依赖于 featureA 中的任何变更,只能从主版本中分支。
git rebase --onto main featureA featureB
featureA 是 <oldbase>
。main
变成 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 丢失的提交
We looked at git rebase
usage with other tools like git reflog, git fetch, and git push. Visit their corresponding pages for further information.
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。