git中的merge和rebase


在使用git进行代码版本控制时,经常会遇到分支合并的情况,而mergerebase都能够实现分支的合并,那么什么时候用merge什么时候用rebase呢。

Branch分支

git中的分支可以理解为是一条条的开发线路,这些线路可能会有重叠的部分,也可能有自己独有的部分,而且不同的线路还可以合并到一起。实质上git中的分支是指向了某个commit的指针,创建分支相当是创建了一个指针,指向某个commit,分支的切换实质上是指针的切换,git中的指针主要有Branch指针(分支指针)和Head指针。

Branch指针

如上图所示,dev分支和feature分支实质上就是分支指针,它们分别指向了各自分支中最新的提交。

Head指针

一个项目中可能会有多个分支,但当前使用的只能是一个分支,Head指针可以理解为是一种标记,它指向了当前正在使用的分支指针。当使用git checkout或者git switch命令切换分支时实际上就是切换Head指针的指向,将Head指针指向了Branch指针。如下图所示,Head指针指向了dev分支指针,即表示当前正在使用的分支是dev分支。
注:一种例外情况,当使用git checkout切换到当前分支的某次commit上时,Head指针的指向将从Branch指针移动到此commit上,并且在内部创建一个匿名分支,这种情况下Head指针处于一种游离状态。开发者在此匿名分支上进行修改之后,可选择保存或者丢弃修改,如果保存修改并进行了commit,那么可以使用git checkout -b [New Branch Name] 命令创建一个新的分支(Branch指针)。

merge命令

如下图所示,假设有一个开发分支dev,以及从dev分支拉取的特性分支feature,然后在feature分支上进行新功能的开发并有了两次提交DE。如果要将feature分支上的内容mergedev分支,考虑到此时dev分支可能没有新的提交也可能有新的提交,就会存在两种情况,这两种情况的merge分别称为快进式合并(Fast-forward merge)和三路合并(Three-way merge)。

快进式合并

如上图所示,如果dev分支没有新的提交,那么feature分支和dev分支其实是在一条链上的,只需要dev分支指针指向到feature分支指针上即可,如下图所示。

三方合并

如图所示,如果dev分支有了新的提交FG,此时两个分支所做的修改会生成一个新的提交E,然后dev分支将会移动到该提交上。具体来说,就是分别将feature分支的提交DE以及dev分支的提交FG,和两个分支的共同祖先C,这三方进行合并并生成一次新的提交H。另外,因为dev分支和feature分支有可能会对同一文件进行了修改,所以三路合并过程中git可能会提示冲突,需要开发者解除冲突后才可完成合并。
注:如果设置git merge时使用了--no-ff(non fast-forward)参数,那么即使满足快进式合并的条件,也会以类似三路合并的方式生成一次新的提交完成merge操作。

rebase命令

如上图左图所示,有dev分支和feature两个分支,它们有共同的祖先C,并且在此基础上还都有两次新的提交,如上节所属,使用merge命令进行合并,将会产生一次新的提交。如使用以下rebase命令进行合并:

git checkout dev
git rebase feature

其中,feature称为基分支,dev称为待变基分支,当执行 rebase 操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。
结合上图解释,就是在执行rebase操作时,git会先将待变基分支dev上的新提交FG提取出来暂存,然后dev分支指针会指向feature分支的最新提交E上,接着暂存的提交FG会接在E后面,最后dev分支指针移动到G上,完成rebase操作。其中要注意的是,虽然rebase操作后端提交FG和之前的提交内容是一样的,但是它们的commit id是不同的,因为它们实质上是用同样的内容进行了行的提交,而且在rebase过程中也可能会存在冲突。

git pull的过程

通常使用git pull命令将本地代码与远端的代码同步,执行git pull命令实际上会先执行git fetch,再执行git merge命令,其中,git fetch表示将远程仓库的所有文件拉取到本地的远程仓库,然后git merge将本地远程仓库的文件与本地仓库中的文件进行合并。但是当使用git pull --rebase命令拉取代码时,在fetch操作之后,git将会运行git rebase命令去合并代码。

总结

  1. 下游分支更新上游分支内容的时候根据情况使用mergerebase
  2. 上游分支(master)合并下游分支内容的时候使用merge
  3. 更新当前正在使用分支的内容时使用rebase

mergerebase虽都能完成分支的合并,但由于其合并原理的不同,拥有不同的使用场景。git merge适合在公共分支上使用,用以将其它分支合并到公共分支,由于merge操作会新生成一个commit提交,因此会留下清晰的合并记录便于追溯合并情况。git rebase适合个人分支(只自己一个人提交)。日常开发过程中,个人分支代码需要和公共分支代码保持一致,定期合并公共分支代码到个人分支,这种场景很适合rebase,可以形成线性提交记录,更加直观。

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - git中的merge和rebase


Carpe Diem and Do what I like