刚开始接触Git时,只会一些常规操做命令:pull、add、commit、push。毕业参加工做之后,在公司的大规模合做中,这时就迫切须要对git进行再了解。而后就系统地学习了git。终于对这些经常使用的命令知其然,知其因此然了,同时,也学习掌握了一些高级命令。其中rebase命令,让我以为发现了git的新大陆。特此记录下相关知识,以作记录,也能够与你们相互学习交流。git
rebase,直接翻译过来就是变基,而这个命令就是这么人如其名。经过rebase命令,咱们能够改变一串commits的基点(父commit)。首先咱们先来操做一遍这个命令,看看效果就知道这个命令是干啥的了。shell
假设咱们的git结构是这样子的。咱们在commit3这个地方开出了一个分支branch1,而后在branch1分支上开发并提交了两个commit(6和7)。同时其余分支合并到master分支致使master分支多了两个提交(4和5)。安全
这时咱们执行如下命令: (注: 此时的活动分支是branch1)post
(branch1) git rebase master学习
执行完命令后的git结构以下:翻译
咱们能够看到,在使用rebase命令以前,branch1和master的交叉点是commit3,这也是branch1的"基点"。经过执行git rebase
命令后,branch1的"基点"就变成了5。从而改变了branch与master的交叉点,如今就是commit5。3d
rebase的工做原理是:Git会让咱们想要移动的提交序列(commit6和commit7)在目标分支(master)上按照相同的顺序从新再现一遍。这就至关于咱们为各个原提交作了个副本,它们拥有相同的修改集、同一个做者、日期以及注释信息。因此执行变基的相关commit是被复制了一份,上图也作了标识,而原先在branch1的commit6和commit7仍是在历史版本中,咱们能够经过commit的sha-1序列号来找到它们,只有在用gc命令执行垃圾回收以后(这个命令git会自动执行,以清理版本库),它们才会真正从版本库中消失。日志
rebase的执行步骤以下:code
经过上面的演示已经原理讲解,你们应该对rebase有了一个基本的了解了。下面说说何时使用它。cdn
当咱们在功能分支上开发完一个功能时,咱们须要将其合并到主分支上(master),继续拿上面的那个例子:
(branch1) git checkout master
(master) git merge branch1
执行完上述命令后,git结构以下:
合并之后会产生一个新的提交节点(commit7)。这样就产生了交叉,出现了"钻石链"。让master分支看起来很乱,也不易维护和管理。
下面看看使用rebase命令的效果。执行如下命令:
(branch1) git rebase master
注:rebase命令是在活动分支执行,而merge命令须要切换到你要合并的分支。因此rebase命令在branch1分支下执行,而merge命令在master分支下执行。这也是二者不一样点之一
执行完上述命令,效果以下
这是branch1尚未合并到master。还需切换回master分支,执行merge命令。执行如下命令:
(branch1) git checkout master
(master) git merge branch1
至此,合并操做正式完成,看下效果:
上面的merge是快进合并(fast-faward),不会产生新的提交。若是须要产生新的提交(为了更好的记录追踪),可使用--no-ff选项,在新版git中支持,旧版不必定支持:
git merge --no-ff branch1
commit6和commit7后续会被清理掉。这样master分支就是一条线,清晰也易于维护和管理。
rebase命令还有一些可选项,利用这些可选项,咱们进行更复杂的操做。下面主要介绍两个--onto和--interactive。
使用--onto移植提交
在以下的git结构中,咱们但愿能将branch1分支和branch2分支同时合并到master。这是咱们能够先将branch1分支中master没有的提交(commit6和commit7)合并到branch2,再经过上面的方法将branch2合并到master。这就是移植提交。能够将commit6和commit7合并到branch2中。
git checkout branch1
git rebase master --onto branch2 上面命令的意思是:将branch1分支中master分支没有的提交拷贝到branch2,执行后的结果以下:
这样就能够将branch1中的提交移植到branch2中。
使用--interactive进行更多操做
给rebase加上--interactive选项,就变成了交互式变基,就是在变基(复制提交)过程当中,会中途中止,而后给咱们一些选择命令,让咱们进行不一样的操做。
举个例子,咱们在feature分支开发一个功能,这其中进行了屡次提交,产生多个commit。但咱们但愿当该分支合并到master时,只产生一个commit,这时就可使用--interactive选项了,下面咱们模拟操做下:
注: 在本地进行rebase以前,建议先pull一下,让远端和本地代码保持一致,由于rebase以后,会改变本地的commit结构,那时若是要同步远端的话,须要强制推,先pull,再rebase,而后再使用
git push --force-with-lease
进行强制本地覆盖远端,就会比较安全且没问题。若是这里看不懂,先往下看。
git checkout -b feature
提交了三个分支。再看下master分支状况:
master最新提交是"Merge branch 'test1'"
接下来,咱们开始进行合并操做:
git checkout feature
git rebase master -i
执行该命令后,变基操做会进入交互状态:
咱们能够看到,上面列出了须要变基的全部提交,顺序从上之下,也是提交从前到后,先提交的commit显示在上面。接下来,就是交互式变基提供的7个命令:
git add . => git commit --amend
进行从新提交。提交完后使用git rebase --continue
继续变基。若是你想修改某个提交,可使用该方法在了解了这些命令后,继续咱们刚刚的任务,上面已经提到过,咱们使用sqash命令合并提交,并从新编辑提交信息。
没有冲突就会变基完成,若是有冲突,解决完冲突后,执行git add . => git rebase --continue
继续变基便可。
变基完成并无合并到master。
注:变基后,feature分支的本地仓库就发生了改变,三个commit合并成了一个。若是你以前将本地分支提交到远端过,就是远端的feature分支仍是有三个提交。这时若是你将本地分支提交到远端,再经过open merge request 合并到master分支的话,你就要注意了。不能执行git pull命令。要使用git push --force-with-lease。强制将本地覆盖远端,这样,本地和远端的分支就同步了。
这里的强制提交有两个参数,--force和--force-with-lease。这两个具体使用和介绍,建议你们Google下,详细了解后再使用。比较功能比较强大。
传送门(为何不用--force而用--force-with-lease)
在实际开发中,通常都是同个Create Merge Request 的方式来合并到master,这样能够进行代码审核。这样,咱们就须要将本地分支push到远端再发起合并。到这步变基完成以后,正如上面所说,远端仓库和本地是不一样的了,这就须要你执行上面的操做,将远端覆盖掉,而后再发起合并。
git push --force-with-lease
若是你能够在本地合并到master的话,那操做就更简单了。
git checkout master
git merge feature
此时,任务完成,可是仍是要提醒一下,若是你以前有提交到这几个commit到远端,那边远端feature分支和本地的就不一样了,如何想同步,就必须强制push了。接下来咱们看看master日志
git log --graph
只有一个提交。若是在feature开发过程当中master有新的提交。也不会出现交叉,就不演示了。
rebase仍是一个比较强大的命令,有些人由于太强大而惧怕使用,生怕出现什么问题,当你真正了解了这些命令的原理之后,你就会以为没有什么能够惧怕的,由于它都在你的掌握之中。掌握rebase -i 这个命令,我相信对git的了解和使用会上一个阶梯,真的比较强大和好用,掌握它,用好它,会帮助咱们提升工做效率。
就这样了吧!欢迎留言交流。