另外一个对rebase的需求可能是:很久以前你曾经启动过一个并行的工作(比如做一些实验,做一些r&d工作),但是一直没有时间就耽搁了下来,现在又有了时间来做这件事情的时候,而这个时候你的R&D工作的base可能已经非常落后了。当你再次来继续这个工作时,你一定希望你的工作是在一个新的bas基础上来进行,以便你可以从已经解决的bugfix或者其他新的ready功能中获益。
最后还有一种场景:实际上是更频繁的场景:实际上并不是变基,而是为了清理你的分支上commits。
在使用git时,我们通常非常频繁地向repo中做commit,但是我们的commit本身往往是零散的不连续的,比如:
我在不同的topic之间来回切换,这样会导致我的历史中不同topic互相交叉,逻辑上组织混乱;
我们可能需要多个连续的commit来解决一个bug;
我可能会在commit中写了错别字,后来又做修改;
甚至我们在一次提交时纯粹就是因为懒惰的原因,我可能吧很多的变更都放在一个commit中做了提交。
上面的各种行为只要是保留在local repo中,这是没有问题的,也是正常的,但是如果为了尊重别人同时也为了自己将来能够返回来我绝对避免将这些杂乱的历史信息push到remote上去。在我push之前,我会使用git rebase -i的命令来清理一下历史。
rebase黄金定律永远不要rebase一个已经分享的分支(到非remote分支,比如rebase到master,develop,release分支上),也就是说永远不要rebase一个已经在中央库中存在的分支.只能rebase你自己使用的私有分支
上面这个例子中展示了已经在中央库存在的feature分支,两个开发人员做了对feature分支针对master做rebase操作后,再次push并且同步工作带来的灾难:历史混乱,并且merge后存在多个完全相同的changeset。
在执行git rebase之前,总是多问问你自己:“有没有其他人也需要这个分支来工作?”,如果答案是yes,那么你就需要思考必须使用一种非破坏性的方式来完成rebase一样的工作(就是需要合入别人的工作成果),比如使用git revert命令。否则,如果这个branch没有别人来使用,那么很好,你可以非常安全地随心所欲地re-write history(注意rebase往往会重写历史,所有已经存在的commits虽然内容没有改变,但是commit本身的hash都会改变!!!)
但是我们要注意,即使对于上面的这个已经分享的feature分支,Bob和Anna也可以互相rebase对方的feature分支,这并不违反上面强调的rebase黄金定律,下面用图例再说明一下:
假如你和你的同事John都工作在一个feature开发上,你和他分别做了一些commit,随后你fetch了John的feature分支(或者已经被John分享到中央库的feature分支),那么你的repo的版本历史可能已经是下面的样子了:
这时你希望集成John的feature开发工作,你也有两个选择,要么merge,要么rebase,
记住在这个场景中,你rebase到John/feature分支的操作并不违反rebase的黄金定律,因为:
只有你的local本地私有(还未push的) feature commits被移动和重写历史了,而你的本地commit之前的所有commit都未做改变。这就像是说“把我的改动放到John的工作之上”。在大多数情况下,这种rebase比用merge要好很多
结论:只要你的分支上需要rebase的所有commits历史还没有被push过(比如上例中rebase时从分叉处开始有两个commit历史会被重写),就可以安全地使用git rebase来操作。 上述结论可能还需要修正:对于不再有子分支的branch,并且因为rebase而会被重写的commits都还没有push分享过,可以比较安全地做rebase我们在rebase自己的私有分支后希望push到中央库中,但是却会由于rebase改写了历史,因此push时肯定会存在冲突,从而git拒绝你的push,这时,你可以安全地使用-f参数来覆盖中央库的历史(同时其他对这个feature也使用的人员可以git pull):