本文转载自微信公众号《小二十七》,作者xiao2shiqi。转载本文请联系小二十七公众号。前言gitmerge应该是开发者最常用的git命令之一。默认情况下,您直接使用gitmerge命令。如果不添加任何选项命令,应该交给git来决定使用哪种合并模式。其实git默认要执行的命令就是gitmerge-ff命令(默认值)。对于专业的开发者来说,你可能不需要每次合并时都指定合并模式(需要的话还是要指定),但你可能需要知道git在幕后。默认情况下您会做什么,以便您的代码万无一失。我们先来说说什么是Fast-forward。我们从一个正常的开发流程来看:开发人员小王接到一个需求任务,从master分支创建一个feature分支。git命令如下:上面的功能开发工作完成,然后生成一个commit,gitcommit-m'Createpopupeffects'[feature5566104106]createpoupupeffects3fileschanged,75insertions(+)再来更新一下README自述文件,让版本差异更加明显。gitcommit-m`updatedmd`这时候我们看看当前分支的git历史。直接输入gitlog--online-all可以看到所有分支的历史:f2c9c7f(HEAD->feature556)updatedmd6104106createpoupupeffectsa1ec682(origin/main,origin/HEAD,main)importdioc5848ffupdatethisreadme8abff90updatethisreadme直接上图可能更好理解一些功能自然会上线之后完成。我们合并代码,完成在线动作。代码如下如果你仔细看上面的文字,你会发现git自动为你进行了Fast-forward操作,那么Fast-forward是什么?fast-forward是指当Master合并Feature时,发现Master的当前节点始终与Feature的根节点相同。如果有变化,Master会迅速将head指针移动到Feature的位置,所以Fast-forward并没有真正合并,只是通过移动指针制造合并的错觉,这也体现了git设计的巧妙。合并后的分支指针如下:通常合并master后会删除功能分支(feature556)。从下图可以看出,Fast-forward模式产生的merge可以产生干净线性的历史:先说什么是non-Fast-forward,刚才说Fast-forward会发生。下面说说什么会导致非Fast-forward。通常,当合并的分支与master没有共同的祖先节点时,此时合并git时默认不能使用Fast-forward模式。我们看下图的模型:可以看到master分支比feature001快了2个版本,master没有办法通过移动head指针来完成Fast-forward,所以在master合并feature001的时候你要做真正的合并,真正的合并会让git做很多工作,具体的合并动作如下:找出master和feature001的共同祖先,三个节点的版本c1,c6,c3(如果有冲突需要处理)新建节点c7,将三个版本的差异合并到c7中,并创建commit将master和HEAD指针移到c7补充:可以看到很多相似之处gitlog:Mergebranch'feature001'intomaster的提交是由非快进生成的。执行以上动作后,最终的分支流程图如下:merge-non-fast-forward如何手动设置合并模式?简单介绍一下gitmerge的三种合并参数模式:-ff自动合并模式:当合并的分支为当前分支Descendents时,则自动执行--ff(快进)模式,而--no-ff(non-Fast-forward)合并模式如果没有匹配就会执行--no-ff非Fast-forward模式:在任何情况下,都会创建一个新的commit用于多方合并(分支被及时合并的是自己的直系后代)--ff-onlu快进模式:只会按照快进模式合并,如果不满足条件(不是当前分支的直系后代),themergerequestwillberejectedandexit以下是官方对三种模式--ff,--no-ff,--ff-only的描述(使用gitmerge--helo查看):Specifyinghowamergeishandled当合并历史已经是当前历史的后代时。--ff是默认值,除非合并一个未存储在refs/tags/hierarchy中其自然位置的带注释(并且可能已签名)的标签,在这种情况下假定--no-ff。使用--ff,尽可能将合并解析为快进(仅更新分支指针以匹配合并的分支;不创建合并提交)。如果不可能(当合并历史不是当前历史的后代时),创建一个合并犯罪。使用--no-ff,在所有情况下创建合并提交,即使合并可以作为快进解决。使用--ff-only,尽可能将合并解析为快进。如果不可能,拒绝合并并以非零状态退出。总结:三种merge模式不好也不坏。最好的解决方案是根据您团队的需求和实际情况选择合适的合并模式。那么应该如何选择呢?我给出以下建议:如果你是一个小团队,追求干净的线性git历史,那么我推荐使用gitmerge--ff-only维护主线模式开发是一个不错的选择,如果你的团队不大不小,他们不追求线性的git历史。为了反映一个比较真实的合并记录,默认的git--ff比较合适。如果你是一个大团队,并且你想严格监控每个功能分支的合并,那么使用--no-ff禁用Fast-forward是一个不错的选择
