使用 Git 已经好几年了,却始终只是熟悉一些常用的操作。对于 Git Rebase 却很少用到,直到这一次,不得不用。

一、起因

上线构建的过程中扫了一眼代码变更,突然发现, ​​commit​​​ 提交竟然多达 ​​62​​ 次。我们来看看都提交了什么东西:

这一次彻底搞懂 Git Rebase_git

这里我们先不说 ​​git​​​ 提交规范,就单纯这么多次无用的 ​​commit​​ 就很让人不舒服。可能很多人觉得无所谓,无非是多了一些提交纪录。

然而,并非如此,你可能听过破窗效应,编程也是如此!

二、导致问题

1.不利于代码 ​​review​​​ 
设想一下,你要做 ​​​code review​​​ ,结果一个很小的功能,提交了 ​​60​​ 多次,会不会有一些崩溃?

2.会造成分支污染

你的项目充满了无用的 ​​commit​​​ 纪录,如果有一天线上出现了紧急问题,你需要回滚代码,却发现海量的 ​​commit​​ 需要一条条来看。

遵循项目规范才能提高团队协作效率,而不是随心所欲。

三、如何合并多次提交纪录?

基于上面所说问题,我们不难想到:每一次功能开发, 对多个 commit 进行合并处理。

这时候就需要用到 ​​git rebase​​ 了。这个命令没有太难,不常用可能源于不熟悉,所以我们来通过示例学习一下。

1.我们来合并最近的 4 次提交纪录,执行:


git rebase -i HEAD~4


2.这时候,会自动进入 ​​vi​​ 编辑模式:


s cacc52da add: qrcode s f072ef48 update: indexeddb hack s 4e84901a feat: add indexedDB floder s 8f33126c feat: add test2.js # Rebase 5f2452b2..8f33126c onto 5f2452b2 (4 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 # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. #


有几个命令需要注意一下:

  • 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

按照如上命令来修改你的提交纪录:


s cacc52da add: qrcode s f072ef48 update: indexeddb hack s 4e84901a feat: add indexedDB floder p 8f33126c feat: add test2.js


3.如果保存的时候,你碰到了这个错误:


error: cannot 'squash' without a previous commit


注意不要合并先前提交的东西,也就是已经提交远程分支的纪录。

4.如果你异常退出了 ​​vi​​ 窗口,不要紧张:


git rebase --edit-todo


这时候会一直处在这个编辑的模式里,我们可以回去继续编辑,修改完保存一下:


git rebase --continue


5.查看结果


git log


三次提交合并成了一次,减少了无用的提交信息。

这一次彻底搞懂 Git Rebase_git_02

四、Rebase 的另外一种使用场景:分支合并

1.我们先从 ​​master​​​ 分支切出一个 ​​dev​​ 分支,进行开发:


git:(master) git checkout -b feature1


这一次彻底搞懂 Git Rebase_2d_03

2.这时候,你的同事完成了一次 ​​hotfix​​​ ,并合并入了 ​​master​​​ 分支,此时 ​​master​​​ 已经领先于你的 ​​feature1​​ 分支了:

这一次彻底搞懂 Git Rebase_2d_04

3.恰巧,我们想要同步 ​​master​​​ 分支的改动,首先想到了 ​​merge​​ ,执行:


git:(feature1) git merge master


这一次彻底搞懂 Git Rebase_2d_05

 图中绿色的点就是我们合并之后的结果,执行:

git:(feature1) git log


就会在记录里发现一些 ​​merge​​​ 的信息,但是我们觉得这样污染了 ​​commit​​​ 记录,想要保持一份干净的 ​​commit​​​ ,怎么办呢?这时候, ​​git rebase​​ 就派上用场了。

4.让我们来试试 ​​git rebase​​​ ,先回退到同事 ​​hotfix​​​ 后合并 ​​master​​ 的步骤:

这一次彻底搞懂 Git Rebase_git_06

5.使用 ​​rebase​​ 后来看看结果:


git:(feature1) git rebase master


这里补充一点: ​​rebase​​ 做了什么操作呢?

首先, ​​git​​​ 会把 ​​feature1​​​ 分支里面的每个 ​​commit​​ 取消掉;

其次,把上面的操作临时保存成 ​​patch​​​ 文件,存在 ​​.git/rebase​​ 目录下;

然后,把 ​​feature1​​​ 分支更新到最新的 ​​master​​ 分支;

最后,把上面保存的 ​​patch​​​ 文件应用到 ​​feature1​​ 分支上;

这一次彻底搞懂 Git Rebase_2d_07

从 ​​commit​​​ 记录我们可以看出来, ​​feature1​​​ 分支是基于 ​​hotfix​​​ 合并后的 ​​master​​​ ,自然而然的成为了最领先的分支,而且没有 ​​merge​​​ 的 ​​commit​​ 记录,是不是感觉很舒服了。

6.在 ​​rebase​​​ 的过程中,也许会出现冲突 ​​conflict​​​ 。在这种情况, ​​git​​​ 会停止 ​​rebase​​​ 并会让你去解决冲突。在解决完冲突后,用 ​​git add​​ 命令去更新这些内容。

注意,你无需执行 git-commit,只要执行 continue


git rebase --continue


这样 ​​git​​​ 会继续应用余下的 ​​patch​​ 补丁文件。

7.在任何时候,我们都可以用 ​​--abort​​​ 参数来终止 ​​rebase​​​ 的行动,并且分支会回到 ​​rebase​​ 开始前的状态。


git rebase —abort