git:rebase的原理
git:rebase的原理
前提:
- 在最近的项目中,我碰到这样一个情况:第一版app上线之后,团队紧接着进行第二版本的开发,由于团队成员对git使用不熟悉,所以开发的每一次提交都是往远端master分支上提交。
- 第一版本打包上线之后,我想让后续的开发中master分支保持代码高可用性,于是在远端建立新的分支
second_version
用于第二版本的开发,到时候再合并到master分支上,奈何有的团队成员不会提交远程其他分支,导致master被污染(如下图)
由于团队成员对git的熟练程度不同,有的使用可视化工具提交,有的使用命令行(比如我),当使用merge的时候会出现如上图所示的问题,点线图错综复杂,原因是在merge时会将本地的提交与拉取的提交融合成新的提交,也就是如图所示的Merge remote-tracking branch...
,并且会将所有的提交显示在点线图上,十分混乱。但是使用rebase的时候,点线图则会很优雅:
点线图是一条直线。网上有很多关于rebase和merge的区别解释,以下分享的是我自己对rebase的观点,希望可以帮助大家理解。
rebase原理
首先大家在开发过程中肯定会经常碰到这样的情况:当你执行git push
时出现错误信息:
这是因为跟你当前分支相关联的远端分支上已经有别人提交了新的代码,或者说你想push的commit的基点已经变更(后面会说明什么是基点)。
-
问题引出:这里涉及到本地分支与远端分支关联的问题,使用
git branch -vv
查看关联关系:
本地master默认与origin/master相关联,当你执行git push
或git push origin master
时,其完整命令是git push origin master:master
,前一个master
是你本地的master,后一个master
是远端master。所以如果没有特别指定,无论你在本地的哪个分支,git push
命令都只会将你本地master分支上的代码进行提交。当你在本地新建其他分支git checkout -b test
,默认是不会与远程分支相关联的。所以当你在该分支上进行git push
时会有如下问题出现
根据提示,使用git push --set-upstream origin test
可以与远端分支test进行关联,这里的test要换成自己的分支名。
回到正题
rebase,故名思意re-base,重新定义基点,当你的代码push不上去的时候,你可以使用git pull -r
或是git pull --rebase
拉取并合并远端分支,然后执行git status
查看是否出现冲突,以下是冲突情况:
红框字的翻译大致是:以'1f618a1'为基点重新定义分支master。1f618a1可以看作是每一次提交的唯一标识码。
我将以下图来讲述rebase的原理:
不同的字母分别代表不同的提交,图中从左到右分别以时间从小到大进行排列。每个commit都以前一个commit作为基点进行开发,例如D是以C为基点进行开发。当我开发完D后,准备push到远端master时,git会进行检查:远端master的最新节点是否是节点D的基点,即检查远端master的基点是否是节点C,如果是,则可以直接push,如果不是,也就是上图的情况:在你push之前远端master已经被他人提交了E和F节点,这时可以执行git pull -r
git会以F节点作为新的基点,与D节点的代码进行融合,如果此时出现冲突,那么你就会被移到临时解冲突的分支,需要人工解冲突,解完后执行git add -A
保存操作,再执行git rebase --continue
继续后续操作,你可能会遗漏某一处冲突,这个完全不同担心,git rebase --continue
会帮你检查是否解决完成,如果没有完成则不会让你回到正常分支。
下图是冲突解决完且顺利执行git rebase --continue
的情况:
可以看到,此时我再执行git push
,就可以顺利将D节点提交到远端master上去了:
可以看到,远端master保持了一条直线,让人看起来非常舒服,这就是rebase的好处,而不像文章开头使用merge那样杂乱、让人迷惑。