使用场景
堪称整个git最完美的功能,辅以squash指令,打造一个最干净,最纯洁,最让人心神荡漾的纯线性git版本历史,让你的git功力迅速提升至神这个级别.
我们利用下面未使用rebase的初始状态来说明
假设你正在你的私有分支experiment分支上工作,解决那一个Bug或者开发完一个新feature,commit改动以后处于 C3。而此时主分支已经变化,从你的experiment拉出来的C2,提升至C4,一般说来这个时候,你会选择Merge,merge是正确的选择之 一,但是会让commit history变得非线性化,也就是说会出现图结构,对于我们diff和bisect都会变得不直观起来,这个时候使用rebase是一个更好的选择。
rebase会把C2到C3之间所有的改动做成一个patch,存到一个tmp file,把你的experiment设置到master的C4状态,然后将patch应用到C4,产生一个新的commit C3′ ,请务必注意,原先的C3将不复存在,这个是和merge的一个很大的区别,也就是C3包含的commit信息都会消失,那么在C3′这个新commit中,须包含相关信息。
无论rebase还是merge都请遵守一个commit对应一个问题/Feature的原则,don't mess it up!!
绝对不要这么使用
就是你已经把你在experiment上的改动commit_A Push到master上,你又心血来潮搞一次rebase,然后又push到master,我们说那你rebase以后呢,你的commit会改变,那 么commit_A就变成那commit_B,但是你的修改本身没有变,push到master以后,你的同事pull master的时候,相当于push了commit_A和commit_B下来,但是改动的本质是一样的,却很可能被系统判断为conflict,产生很 多很多匪夷所思的问题,整个版本树,也会变得非常奇怪起来,这下我们所有人都会愤怒,小倒霉蛋,够你喝一壶的那。
所以千万记住: push那你的commit以后,就别再对这个commit做rebase!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
使用方法
- 首先给出,使用rebase前的一个状态
- 使用merge以后的状态
- 使用了rebase以后的状态
$git checkout experiment $git rebase master
- 回到master,merge experiment分支的改动,产生一个fast-forward merge
$git checkout master $git merge experiment
其它
rebase互动模式
当你在experiment上的commit非常频密,比如17,18次(git鼓励频繁commit,这是好习惯),你rebase的时候不希望保留他们,而是把它们合并再一次,变为一个新的唯一的commit,那么下面的命令很适合你
$git rebase --interactive master
接下来你设置的编辑器会跳出来,需要你来指定需要squash到一起的commit
pick ccd6e62 Work on back button squash 1c83feb Bug fixes squash f9d0c33 Start work on toolbar
这样ccd6e62,1c83feb,f9d0c33 代表的三个commit就会合并到一起 。当我保存并关闭之后,会出现一个新的文本编辑器提示我为这些合并后的commit填写一个commit message,然后一切就绪。
rebase的撤销
某种情况下,你的rebase输出是Interactive rebase already started,而你确发现在做interactive
rebase的时候你的action(pick,squash)指定错误啦,ok,让我们回滚rebase吧,1234,再来一次 <cr>
git rebase --abort
修改bug时的注意事项
在bug fix时,我们需要在bugzilla填写commit id。同时,由于我们最近使用了git rebase的方法,在填写commit id时有可能出现错误。原因如下:
在修改一个bug时,总共会有两个commit id
- 在私有分支上git commit后产生的commit id
- 在共有分支上git rebase后产生的commit id
注意:这两个id是不一样的。应该使用第2种commit id。因为第1种commit id会变为无效的id。