为什么要变基
Git官方文档中提到:
在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase。
merge也就是合并,这个概念很容易理解,从分支上拉取代码进行修改,再提交的时候,如果遇到了别人的修改,则把修改和他们的修改合并一下。那么rebase中文译为变基是什么意思呢?
首先要理解这个base,base也就是基础的意思,当从代码分支上获取代码的时候,就有了一个基础,也就是base,此后的修改都是在这个基础之上进行的,但是当需要提交修改的时候,遇到了别人的代码,变基这个操作就是在这个时候,不去合并别人的代码,而是直接把原先的基础变掉,变成以别人修改过后的新代码为基础,把修改在这个新的基础之上重新进行。基础变掉了,所以叫作变基。
那么,变基有什么好处呢?好处之一是可以使时间线变得非常干净,以前采用合并的时候,时间线里完整记录了代码是从哪个基础上拉取出来的,做了哪些修改,然后又在哪个时间点合并回分支去,而采用变基之后,时间线上不再反映拉取的时间点,因为每次提交都是以最新代码为基础的,所以时间线就变成了一根直线。
下面拿两个真实例子给大家更直观地看一下:
这是采用自动变基之前的时间线,可以看到,各种混乱:
这是采用自动变基之后的时间线,非常整齐,可以很清楚地看到哪一次修改之后又发生了什么修改,而不是多次修改纠缠在一起:
自动变基
虽然网上关于变基的教程很多,但是一般初学者总会感到茫然,不敢轻易下手,怕万一把时间线弄坏了,一发不可收拾。而且所有关于变基的命令都和已经多年习惯了的pull/add/commit/push不一样,很多图形化的工具例如vscode也不直接支持rebase
这样的命令,都需要手工输入,繁琐而且容易出错。直接用两条命令设置一下,从此以后每次提交都可以自动变基,而不必改变之前的任何操作习惯。这两条命令就是:
git config --global pull.rebase true
git config --global rebase.autoStash true
这两条命令在任意一台电脑上都只需要设置一次,而且一次设置,全局生效,所有的项目以后每次pull/push都会自动变基,再也不用担心在提交之前忘记变基了。
原理
如果不想了解原理的话,则执行完上面两条命令就可以去开心地变基了,完全没有问题。如果想了解一些原理,可以接着往下看。下面来详细解释一下这两条命令的原理:
首先,要搞清楚一点:什么时机是变基的时机?一般理解是推送的时候,其实不是,而是从拉取的时候就要开始变基了,因为拉取的时候,服务器上可能已经有新代码了,所以要变基也是在这个时候,一旦发现有新基础了,则立马变掉。
所以,通常情况下,拉取新代码无非就是一个命令:git pull
,但现在要变基拉取,就需要用git pull --rebase
。但是每次这样执行命令就会很麻烦,而且在vscode里也没有办法自动加这个参数,所以为了方便起见,就设置一下第一条命令,这样每次拉取它都会自动变基。
但是自动变基往往会带来一个额外的问题,那就是每次当手头有正在编辑的文件的时候,它就说它无法变基,因为工作区不干净。为什么不变基的时候没有这个问题,而一旦选择了自动变基,工作区就必须保持干净呢?因为变基的操作原理是它需要先把本地代码库里还没有推送的那部分提交反向释放到工作区,然后从服务器拉取新代码,再以新代码为基础把工作区里的修改附加上去,因为有这个过程,所以它必须要求服务区是干净的。
为此git提了两个建议:要么把所有修改先全部都commit
到本地,要么把它们都stash
保存起来。首先说,commit
肯定不是一个好主意,因为很有可能这时候工作做到一半,还不适合commit
,如果每次pull
都commit
一下的话,那么分支树上会多出很多无用的节点。
那只剩下最后一个选择,就是每次pull
之前都stash
一下,pull
完了之后再把stash
的内容pop
出来,但这样岂不是更麻烦?所以这里用第二条命令设置一下,每次rebase
的时候都自动把工作区里的内容自动stash
进去,rebase
完成之后再自动恢复出来。
其余要注意的就是有冲突的时候,如果有冲突,则合并完冲突之后,执行一下git rebase --continue
就好了,其它和原先的用法没有任何区别。