Git - rebase
rebase是什么?
re(变、重新定义)base(基础、基本)。rabase,也叫变基,即在当前分支外的另一点上重新应用当前分支的提交历史,是Git整合变更的另一种方式。
那么,为什么说是另一种呢?
因为还有一种就是我们经常会用到的merge。rebase和merge一样,都是用来整合变更的,只不过是整合的方式不一样。
merge 命令
merge 命令是整合分支最简单的方法,它会将两个分支最新的快照以及两者最近的祖先进行三方合并,最后生成一个新的快照,像下面这样
上面的图片中,我创建了一个本地仓库,进行了一次叫做A1的提交,然后创建了dev分支,再然后分别再dev分支和master分支上做了修改,最后在master分支上执行了git merge dev 的命令,生成一个叫做A6的新的提交,而A6中就包含master分支和dev分支的全部修改内容。这样就完成了一次分支的和合并过程。
合并完成之后,我们查看一下这个项目的提交历史
和第一张图片的轨迹是一样的。
merge合并的优点:可以清晰的看到每次commit的情况以及每个分支的详情。
缺点:每次合并分支都会产生一个merge commit ,所以我们的提交历史看起来会很乱。
那怎么办!!! 没有关系
rebase命令
rebase命令可以帮我们把整个提交历史变成干净清晰的一条线。处女座、强迫症首选。
同样的操作流程,我们执行 git rebase dev命令之后,再看一下提交历史
可以看出来,很简洁,很清楚 。
rebase命令的优点:可以得到更简洁的项目历史,去掉merge commit。
缺点:重写了提交历史,不能清楚的了解原始提交。
仔细对比两次提交历史
可以发现不光只是提交历的轨迹发生了变化,每次的提交顺序也发生了变化。
那为什么会发生这样的变化呢?
首先是merge命令,最开始我们说merge合并进行的其实是一个三方合并,那这三方是怎么进行合并的呢?首先将master分支和dev分支的提交合并成一次新的提交,然后将主合并分支(当前执行merge命令的分支)的HEAD指针指向新生成的这次提交。这就是merge合并的过程。
其次是rebase合并,rebase合并分支是先将主合并分支(当前执行rebase命令的分支)的提交暂存起来(或者就是说将这些提交给拿下来了),暂存之后其实主合并分支上就已经没有之前的提交了,然后再将dev分支的提交合并到主合并分支上(也就是我们现在的master分支),最后再将我们之前暂存起来的提交放到当前分支上。最后就成了我们看到的这种顺序。
--interactive指令
功能:--interactive指令用来修改提交历史(合并提交历史)
被操作的提交:
当前分支的提交
参数:
一个参数:某一特定提交对象的ID或执行特定提交对象的指针(HEAD),
两个参数:某两次特定提交的ID
命令格式:
git rebase -i 参数 或 git rebase -i 开始参数 结束参数
输出:
该提交对象之后的所有提交对象(不包括该提交对象)或 两次提交对象之间的所有提交对象(不包括第一个参数,但包含第二个参数)
--onto指令
开发过程中可能会有这么一种情况,我们从主干切出某一分支issue1,做了一些修改并进行了几次提交,此时,有另一个需求,我们在issue1分支切出新分支issue2用来开发新的需求,同样的做了一些提交,在这期间其他成员对master主干分支进行了更新,过程如下:
假如现在,issue2分支开发完成,我们需要将其并入主线,但是issue1分支的变更还是继续保持独立,此时我们就不能直接执行git rebase,因为这样做issue1分支上的cec214、d4eb57也会被合并入主线上,而我们并不想要它。这时我们就需要使用git rebase --onto命令:
执行git rebase --onto master issue1 issue2 命令之后,分支的结构变成下图:
可以看出,执行完上述命令之后,在主合并分支上复制了issue2分支上的全部提交对象,并在主线上生成对应的新的提交。然后将issue2的指针指向最新的一次提交。
需要注意的是,执行完命令之后,master分支的指针并没有指向最新的提交,所以最后我们需要进行手动合并。
其实选择变基还是合并,主要看具体需求,你如果只是想要一个清晰,明了的历史,并不关心历史的具体来源,你可以首选变基,但是如果你想比较清楚地了解项目不同阶段的原始历史,选择用merge直接合并更加合适。
最后,提醒小伙伴们
永远不要对已经推到主干分支服务器或者团队其他成员的提交进行变基,我们选择变基还是合并的范围应该在自己当前工作范围内。