详解git rebase,让你走上git大神之路

在之前的文章当中我们介绍了git merge的用法 , 明白了通过git merge我们可以合并两个分支的改动 。 这样我们就可以很方便地进行协同开发了 , 每个人都在自己的分支下开发代码 , 开发完毕之后再一起合并到master分支 。 通过这种方式可以保证大家的代码不会陷入混乱 , 但是这样有一个隐含的缺陷 。
缺陷就是我们之前说过的 , 当我们合并两个没有上下游关系的分支时 , git会自动替我们生成一个merge commit , 记录此次的merge 。 记录merge操作没有什么问题 , 问题是如果我们遇到特殊情况需要反复merge的时候 , 就会导致commit的提交记录非常混乱 , 你根本分不清什么是什么 。 尤其是当你merge了一个巨大改动的分支之后 , 你的git log基本上就不用看了 , 肯定全都是其他人的各种乱七八糟你也不清楚的提交记录 。
为了解决这个头疼的问题 , 我们就需要用到rebase操作 。
rebase简介rebase是一个非常强大的操作 , 可以实现一些神奇的功能 , 但是强大也意味着有隐患 , 因为如果使用得不好可能给团队的代码造成非常大的问题 , 成为团队当中被无情指责的背锅侠 。 所以我们在使用之前一定要先了解清楚原理 , 之后再小心谨慎地使用 , 否则很有可能会产生问题 。
首先说说rebase的功能 , rebase的功能说白了可以提取我们在A分支上的改动 , 然后应用在B分支的代码上 , 完成类似于补丁的功能 。 我这么说非常空洞 , 我从learngitbranching.js.org网站上截取了一些图 , 会清晰一些 。 另外推荐一下这个网站 , 当中有一些图形化的演示和实操功能 ,我们可以在上面练习我们学到的git命令加深印象 。 但是它也有一个缺点 , 就是一些细节介绍得比较少 , 这也是我没有一开始的时候就推荐给大家的原因 。
详解git rebase,让你走上git大神之路文章插图
这张图非常经典 , 是很多场景下的常态 。 C1是线上的版本 , 在C1的代码上线了之后我们发现了一个bug , 于是我们checkout了一个叫做bugFix的分支 。 与此同时还有新的功能在开发 , 新的功能提交到了master之后形成了节点C2 。 这个时候我们在bugFix分支当然可以merge master这没有什么问题 , 但是也可以rebase master , rebase之后整棵git树会变成这样:
详解git rebase,让你走上git大神之路文章插图
这个结果就好像是我们先到了C2然后checkout出了bugFix分支 , 然后在bugFix分支上将之前写过的代码重新写了一遍 。 这样的操作就是变基 , 当我们rebase了之后再提交合并请求我们的合并记录里面会非常干净 , 没有多余merge的信息 。 对于多人协同开发的场景非常有帮助 。
更牛的例子上面只是一个rebase操作的基本应用 , 通过rebase操作我们还可以实现更加炫酷的功能 。 我们来看这样一张提交图:
详解git rebase,让你走上git大神之路文章插图
这张图也非常经典 , master是正常的线上分支 , 在C2节点处代码上线 。 上线之后继续开发新的需求checkout了新的分支feature , 与此同时master也经过了一些合并 , 合并了另外的一些改动到了C4节点 。 之后新的分支feature开发完成了一个重要性能提升的改动C5 , 这时 , 我们发现了线上代码的一个bug并且性能不佳 , 我们需要紧急修复 。 于是在C5处checkout了新的分支bugFix , 我们在bugFix分支当中修复了bug , 想要发布上线 。
这时候feature分支继续开发到了C6节点 , 仍然没有开发完成 , 也没有经过系统测试 。 所以我们并不希望C6的代码发布上线 , 我们希望合并进入master的代码之后C5 , C7和C8 。 我们只需要在bugFix分支rebase到master , 然后修复冲突之后提交 。 提交完成了之后 , 我们再checkout到master把bugFix分支merge进来 。 整个流程如下:
git checkout bugFixgit rebase mastergit checkout mastergit merge bugFix最后我们得到的结果会是这样:
详解git rebase,让你走上git大神之路文章插图
我们继续问一个问题 , 假如我们只需要合并bugFix分支自己的改动 , 不希望把C5节点也合并进来 , 我们应该怎么办?如果不用rebase会非常麻烦 , 我们很难处理 。 有了rebase之后非常简单 , 我们只需要使用onto参数 , 它可以限制我们rebase从什么地方开始 。
比如我们希望rebase的内容是在bugFix这个分支当中不在feature分支里的内容 , 我们可以这么写:
git rebase --onto master feature bugFixgit执行这条命令的时候会先找到feature和bugFix的共同祖先 , 然后将共同祖先之后的部分rebase到master 。