基本功能
git 的rebase相信很多同学都有耳闻,但是可能一直没有尝试过如何使用。
base顾名思义,是基线的意思,一个完整的代码提交历史,就如果时间上的历史,是一条直线,
上图的时间线表示了古欧洲的历史,可见是一条直线,没有分支。
但是实际上在版本开发过程中,实际上这样是过于理想的。实际上的情况如下:
我们在版本中,提交了D-E,此时我们需要一个特性分支topic,单独开发;于是我们就有了topic分支和master两个;
有强迫症的同学,肯定希望最终的版本主干还是一条直线,于是想把A-B-C强压入master中。
这时候rebase就派上用场了。
强拉一根线——强扭的瓜,至少看上去舒服
这里我们不讨论将topic分支压入主干是否合理,如果要这样做,我们应该这么操作呢?
首先,git checkout 两个分支到本地,
其次,git pull 保证两个分支都是最新
最后,执行git rebase master topic ,
如果你当前正在topic分支上,可以省略最后一个参数,即git rebase master
执行后(假设没有任何冲突),主干就变成如下的直线了。 这里的A’,B’,C’虽然还是之前的三笔提交,但是他们的hashcode已经变化,对于git来说他们是新的节点,只是内容还是之前的A,B,C,所以这里加上一撇来标记。
不过,当前你的分支还是topic,只是历史从 D-E-A-B-C变成了 D-E-F-G-A’-B’-C’,(没有冲突的情况)代码没有任何变动,但是提交跟远端的完全不一样了。
所以在提交远端时,需要强行推送。
如果你就像修改master,让master保持一根线,那么命令如下,
git push -f origin topic:master
但是不要轻易执行这种命令,尤其是在master上,这里只是出于示例目的!!!
清理被污染的提交记录
当然rebase的另外一个重要作用是,清理被污染的提交记录。
比如,某分支,存在大量如下提交记录。
对于这种重复commit内容,是一种很不好的习惯,首先它对其他开发人员,甚至是自己来说,都是没有任何帮助的。另外大量的无用内容,就是一种污染。
对于这种情况,强迫症的福音又来了,rebase。
这种情况下,只需要操作一个分支, 所以直接执行
git rebase -i <HEAD~n>
这个标识从HEAD往前数n个提交记录需要rebase
或者 直接找一些要rebase的提交记录id
git rebase -i <commit-id>
执行后会出现一个交互界面,下面是所有的提交,同git log --oneline ,但是顺序是反的,这里是按时间升序。第一行是最远的提交。
每一行提交前面有一个pick,这里的含义在交互界面的最下方也有介绍。
- pick 是使用该commit
- reword 是使用,但是修改提交记录
- edit 是使用,但会停下来做amending
- squash 是使用,但把提交记录合入到上一个commit中
- fixup 是使用,但丢弃提交记录
这里根据你的需求,比如大量重复的log,就选fixup。 注意一下,第一条记录,也就是最远的提交,必须是pick。
修改好,就wq退出。退出后开始执行rebase操作。这里如果遇到冲突,rebase会停下,等你合并完冲突后,执行rebase --continue 继续。 如果你发现操作有问题,可以执行rebase --abort 停止rebase操作,一切会回复原样。
这里需要讨论一下两种情况。
- 所有提交都是在你本地,你的rebase其实不会与远端分支有任何冲突,所以rebase后,你可以直接普通push
- 所有的提交或者部分提交在远端,那么你的rebase必然跟远端是不一致的,所以需要git push -f来覆盖你远端的分支。
|