前言
在多人协作开发中,不同的开发者经常在不同的分支进行开发,最后会将变动合并到主分支上。在 git 中,merge 和rebase 都可以用来合并分支。那么,merge 和 rebase 又有什么不同呢。
merge
在 master 分支创建一个名为 aqi 的文件,先写入1,然后执行 add、commit 提交到本地仓库,然后分两次分别写入2和3,执行上述操作。在整个过程中,文件 aqi 一共被 commit 提交了三次,也就是有三次提交记录。
然后在此基础上,创建 dev 分支,这时候的 dev 就像是 master 分支的"镜像",两个分支具有相同文件内容以及提交记录。
如果 master 分支不做任何变更,这时候我在 dev 变更 aqi 文件的内容,新增一行4,然后提交到本地仓库。
在可视化界面中可以看到 dev 分支基于是基于 master 的第三次提交进行的变更。
这时候切换到 master 分支合并 dev 分支的变更。
bash
git merge dev
这样 dev 分支的变更就被合并到 master 分支上了。
fast-forward模式
fast-forward 是 merge 的快进模式,如果当前的分支没有任何新的commit,而另一个分支包含了一些新提交时,git 会直接将当前分支快进到目标分支的最新提交,而不创建额外的合并提交。。
例如在上面的提交记录中,master 内容是 1、2、3,dev 文件内容的是 1、2、3、dev4。dev 是全包含于 master 的,所以这里使用的就是快进模式。
从上图可以看到,提示中有 fast-forward,表示直接将两个分支合并,不创建新的 commit,移动两个分支的指针指向 dev 的 commit,此时 dev 的 commit 属于两个分支。
通过 git log 查看提交日志,master 分支已经有了 dev 之前的提交信息。这里要注意的是,master 分支直接使用了 dev 分支的提交信息。
如图,master 分支的 HEAD 指向 dev4 这个提交信息。
no-fast-forward模式
no-fast-forward模式:
- --no-ff 指定 no-fast-forward 模式合并分支
- 如果两个分支在同一个基点之后都有各自的提交历史,合并时会使用非快进模式
1. --no-ff
使用 git reset 将 master 分支恢复到合并前的状态。
此时 master 分支只有3个提交信息,dev 是4个。使用 --no-ff 指定 no-fast-forward 模式合并分支。
bash
git merge dev -m'master4' --no-ff
我们知道 -m 是 commit 时,用来指定提交信息的参数。这里在合并之后,使用 git log 查看提交日志,除了有 dev4 这个提交信息,也多了上面命令指定的commit信息。
也就是说,在 --no-ff 模式下,当前分支合并之后会新建一个commit。我们可以查看可视化提交信息来理解。
如图,这里 master 分支的 HEAD 不再指向 dev4,而是指向合并后新建的commit。
2. 新提交
我在 master 分支上,基于提交3创建了一个文件作为新变更(修改同一文件会冲突),然后提交信息为 master4。
如图所示,master 和 dev 分支都有共同的祖先,都基于3节点做了新的变更提交。这里执行 git merge dev 合并分支。
如图所示,和指定 --no-ff 相同,都创建了新的提交信息。
rebase
git rebase 是另一种合并分支的方式,它通过将一个分支的提交移到另一个分支的基础上,重新应用这些提交。与 git merge 不同的是,git rebase 不会创建合并提交,而是将两个分支的提交历史线性化,重新排列提交记录。
和上面 merge 的前置条件一样,在 master 中有三次 git 提交记录,在此基础上,我们创建 dev 分支,然后变更文件再次提交一次。这时我使用 rebase ,将 dev 分支合并到 master 分支。
这个结果就和 git merge 的 fast-forward 模式一样,不会生成自己的提交信息,而是使用 dev 分支的提交信息。
但是在多人协作的开发中,很少有这种全包含的情况,基本上就是从一个 commit 的基点拉出分支,然后各自开发各自的,最后开发完成进行合并。
merge 合并
回退到合并前的状态,master 和 dev 分支都基于第三次提交之后再做变更,这时候两个分支提交信息如下图(绿色是master)。
这时执行 git merge 合并分支。因为 master 和 dev 两个分支在同一个基点之后,都有各自的提交历史,这时 git merge 合并分支,就会生成一个新的 commit 信息,然后 master 将 HEAD 指向最新的这个提交。
rebase 合并
再次回退到 merge 合并前的状态,执行 git rebase dev 来合并。
如图,因为 dev4 的变更提交早于 master4 的提交,所以 dev4 的提交就被合并到了 master4之前。也可以从可视化界面查看提交日志:
如图,rebase 合并不会创建新的 commit 信息。