前一篇介绍的Git-如何解决合併冲突,说明了在合併过程中可能遇到的冲突。
成功合併之后也有可能遇到另一个情况,「fast-forward(快转模式)」。
何谓快转模式
这是上一篇成功合併的线图。
把feature分支删除,并且在master分支上,再重建一个feature分支。
此时,feature分支与master分支,都是同一个版本。
在feature分支:
执行cat,查看a.txt的内容。
将内容改成123。
执行git diff查看修改前后的差异。
commit新版本
feature分支比master分支领先一个版本。
为了让fast-forward(快转模式)更明显,再新增2个档案。
这样一来,feature分支会比master分支领先3个版本。
在master分支合併feature分支。
这时会发现,一个讯息:Fast-forward
表示这次的合併,採用了fast-forward(快转模式)。
那fast-forward(快转模式)究竟是什么情况?
查看log
目前,master分支跟feature分支位于同一个版本,这是可以预期的情况,毕竟是master分支合併feature分支。
来看看线图。
重点来了,跟上一张线图比较后,会发现master分支从(Merge branch 'feature')版本直接跳到跟feature分支同一个版本(add c.txt)。
线图并无分岔,而是一条线直接跳上去(黑色)。
这种线图没有分岔,而直接跳到最新版的情况,就是fast-forward(快转模式)
分析fast-forward
一开始,feature分支与master分支,是同一个版本。
意味着,它们拥有相同的档案与内容。
然后,feature分支commit了3个新版本。
也就是领先master分支3个版本。
当master分支要合併feature分支时。
它们之间的差异,就只是feature分支比master分支多3个commit而已,其他都是一模一样。
换句话说,master分支有的feature分支都有。
毕竟它们都是从同一个commit分出去的。
master分支合併feature分支,就等同于合併自己以后的版本。
此时,git就会启用fast-forward,master分支一口气跳了3个版本,
到feature分支最新的commit(add c.txt)。
关闭fast-forward
表面上看来,fast-forward合併,并没有任何问题,结果也都成功合併。
但请仔细思考,分支的意义是什么?
在软体开发过程中,会有一条主要分支,其他分支,不管它的任务是什么,最后,都会併入主要分支。
master分支是主要分支,而feature分支是开发中的分支,master分支直接跳到feature分支的最新commit,是有点奇怪。
这边要强调,以git的观点,fast-forward没有不好,我们是以软体开发的观点来讨论这个问题。
解决方式就是将fast-forward合併关闭,让master分支与feature分支的合併,看起来就像是开发中的分支(feature)併入主要分支(master)。
执行git reset --hard ORIG_HEAD,回复合併之前的版本。
master分支回到原本的版本。
再次合併,这次关闭fast-forward。
指令 --no-ff,关闭fast-forward。
执行git merge feature --no-ff。
这次合併讯息,没有Fast-forward字样。
确实执行分支合併的动作。
由线图可以看出,master分支的确合併feature分支,并做了一次commit(Merge branch 'feature')。
合併之后,feature分支可以再继续开发,再继续併入master分支。
feature分支再新增档案。
再次併入master分支。
这样的线图非常一目了然。
fast-forward的缺点
一般来说,我们不会在主要分支,执行开发、修复、测试这些操作,一定都是确认稳定后,再併入主要分支。
从线图上可以看出哪些分支做了哪些commit,再合併入主要分支。
master分支的黑正方,表示合併后的commit,黑圆点,表示自身的commit,
红圆点表示feature分支的commit,这样不是很清楚吗。
但如果透过fast-forward合併的话,并不会产生合併的commit,且全部的commit都挤在同一条线上,包括master分支,如此一来,我们就很难判断分支commit的情况。
那到底fast-forward适合用在什么情况呢?
适合fast-forward的情况
我们先在GitHub,新建一个repository,并上传本地专案。
详细步骤可以参考Git-上传档案至远端储存库
上传成功后可以发现,多了一个origin/master分支,代表远端储存库的master分支,
目前跟本地端的master分支指向同一个版本。
查看前5笔的log
master分支(本地)与origin/master分支(远端),虽然是不同分支,但它们意义上是相同的,都是master。
所以它们应该要同步才对。
我们来模拟一个多人分工,大家都在origin/master分支开发的情境。
将专案clone下来,跟原本的範例不同位置。
模拟同事A的开发。
详细步骤可参考Git-git clone 的各种方式
假设同事A修改b.txt后,push至远端储存库。
这时,远端的origin/master分支有16个commit。
而本地端的master分支有15个commit。
所以远端的origin/master分支领先本地端的master分支一个版本。
必须得将远端的origin/master分支下载回来,才能更新版本状态。
执行git pull,可以下载更新。
但实际上git pull是由两个命令所组成的:git pull = git fetch + git merge。
也就是说,它会执行两个动作。
将变更的部分先下载回来(git fetch),再执行合併(git merge)。
执行git fetch
查看线图。
origin/master分支领先master分支一个版本,这是由同事A所push上去的。
既然已经有新版本了,那就得将master分支合併origin/master分支,我们跟同事A的专案才能同步。
重点注意,这时要採用哪种合併呢?
刚刚我们将fast-forward关闭,是因为master分支与feature分支,意义上是属于不同的分支,才需要让线图分岔。
但目前的情况是,master分支与origin/master分支,意义上都是相同的分支,既然如此,那直接让master分支一直线上去,是比较合乎逻辑的。线图分岔,反而会觉得奇怪。
採用fast-forward合併。
让master分支直接跳到origin/master分支的版本。
结论
使用fast-forward的情况:合併的分支,代表相同的意义。
关闭fast-forward的情况:合併的分支,代表不同的意义。
本文为观看网路教学的学习笔记。