Git 是最流行的代码版本控制系统,这一系列文章介绍了一些 Git 的高阶使用方式,从而帮助我们可以更好的利用 Git 的能力。本系列一共 8 篇文章,这是第 6 篇。原文:Interactive Rebase: Clean up your Commit History[1]
交互式 Rebase 是 Git 命令中的瑞士军刀,有很多用例和可能性,对任何开发人员的工具链都是极好的补充,允许我们在与团队成员分享工作之前修改本地提交历史。
我们看看使用交互式 rebase 可以做些什么,然后看一些实际的例子。
Git 进阶系列:
- 创建完美的提交
- Git中的分支策略
- 基于Pull Request实现更好的协作
- 合并冲突
- Rebase vs Merge
- 交互式Rebase(本文)
- Git中的Cherry-pick提交
- 用Reflog恢复丢失的提交
重写提交历史
简而言之,交互式 rebase 允许操作、优化和清理提交历史。你可以…
- 修改提交信息
- 合并多个提交
- 拆分、编辑已有提交
- 对提交重排序
- 删除提交
请记住,交互式 rebase 会重写提交历史,所有涉及的提交都将获得新的哈希 ID。另外,简单提醒一下: 提交 id 是用于识别提交的,是 SHA-1 校验和。因此,通过改变哈希,在技术上来说我们创建了全新的提交。这意味着不应该在已经推送到共享远端代码库的上使用交互式 rebase。其他团队成员的工作可能就基于这些提交,当我们使用交互式 rebase 重写提交历史时,就改变了这些基础提交。
所有这些都意味着交互式的 rebase 是为了帮助我们在合并(并可能推入)到共享的团队分支之前清理和优化自己的本地提交历史。
交互式 rebase 工作流
在我们进行交互式 rebase 测试之前,先看看一般的工作流。无论做什么,删除提交、更改提交消息、合并提交……这些步骤都是相同的。
第一步是确定要操作的提交的范围,想回到多久以前?一旦有了答案,就可以开始交互式 rebase 会话了。在这里,我们有机会编辑提交历史,比方说可以通过重新排序、删除、组合提交等方式操作所选择的提交。
在第一步中,总是要通过查看提交历史记录了解当前状态,可以使用git log
命令来检查项目的历史并显示提交日志。
下面是本文使用的示例代码库:
检查完后,就可以开始工作了。我们一步一步来,在示例中,我们将做以下事情:
- 首先,修改旧的提交信息。
- 其次,合并两个旧的提交。
- 然后,分解一个提交。
- 最后,删除一个提交。
修改提交信息
许多情况下,我们希望更改最近的提交。请记住,这个场景中有一个不涉及交互式 rebase 的捷径:
$ git commit --amend
这个命令会打开默认的文本编辑器,可以修改最近提交的内容和信息。我们可以更改、保存并退出编辑器。该操作不仅可以更新提交信息,还会有效的更改提交本身并编写一个新的提交。
如果已经将上次提交的文件推送到远端代码库,同样请小心,不要修改它!
对于任何其他提交(任何比最近一次更早的提交),都必须执行交互式 rebase。要交互式运行git rebase
,需要添加-i
选项。
第一步是确定基础提交: 要更改的提交的父提交。可以通过使用提交的哈希 ID 或执行少量计数来实现这一点。要更改最后三个提交(或者至少其中一个),可以这样定义父提交:
$ git rebase -i HEAD~3
该命令会打开一个编辑器窗口,可以看到所选择的三个提交(我说的“选择”是指提交的范围: 从HEAD
一直到HEAD~3
)。和git log
不一样,这个编辑器将最老的提交(HEAD~3
)显示在顶部,最新的在底部。
在这个窗口中,实际上并不需要更改提交,只需告诉 Git 要执行哪种操作。Git 为此提供了一系列关键字,在我们的示例中,将单词pick
更改为reword
,这允许我们更改提交信息。保存并关闭编辑器后,Git 将显示并允许更改实际的提交信息。保存并再次退出,就这样!
合并提交
下一个示例,我们将两个提交(“7b2317cf Change the page structure”和“6bcf266 Optimize markup”)合并成一个提交。同样,第一步需要确定基础提交。我们至少需要回到父提交:
$ git rebase -i HEAD~3
编辑器窗口再次打开,但这次我们输入的不是reword
,而是squash
。确切地说,我们在第 2 行中将pick
替换为squash
,以便将其与第 1 行合并。记住这一点很重要: squash
关键字会将标记的行与它上面的行合并起来!
保存更改并关闭窗口后,将弹出一个新的编辑器窗口。为什么?因为通过合并两个提交,我们创建了一个新的提交!而这个新的提交需要一条提交信息。输入信息,保存并关闭窗口……这样就成功合并了两次提交。多么强大!
最后,给那些使用“Tower”Git 桌面 GUI 的人一点“专业提示”: 为了执行 squash,可以简单的在提交视图中互相拖放提交。如果想要更改提交信息,只需右键单击问题中的提交,并从上下文菜单中选择“Edit commit message”即可。
删除提交
最后的例子将介绍一个大家伙: 从提交历史中删除一个修订!为此,我们使用 drop 关键字来标记想要删除的提交:
drop 0023cdd Add simple robots.txt pick 2b504be Change headlines for about and imprint pick 6bcf266 Optimizes markup structure in index page
这可能是一个很好的时机来回答一个你可能已经思考了一段时间的问题: 如果正在进行 rebase 操作,并认为“哦,不,这不是一个好主意”,你能做什么?没有问题,可以随时中止!只需输入以下命令,代码库就会回到 rebase 之前的状态:
$ git rebase --abort
改变历史
这些只是交互式 rebase 所能做的一些例子,还有很多其他方法可以控制和修改本地提交历史记录。
如果想更深入了解高级 Git 工具,可以免费查看“Advanced Git Kit[3]”: 这是关于分支策略、交互式 Rebase、Reflog、子模块等主题的短视频集合。
References:
[1] Interactive Rebase: Clean up your Commit History: https://css-tricks.com/interactive-rebase-clean-up-your-commit-history/