前言

git merge 应该是开发者最常用的 git 指令之一,

默认情况下你直接使用 git merge 命令,没有附加任何选项命令的话,那么应该是交给 git 来判断使用哪种 merge 模式,实际上 git 默认执行的指令是 git merge -ff 指令(默认值)

对于专业的开发者来说,你可能无须每次合并都指定合并模式(如果需要的话还是要指定的),但是你可能需要知道 git 在背后为你默认做了什么事情,这样才能保证你的代码万无一失。

先说说什么是 Fast-forward

我们从一个正常开发流程来看看:

开发者小王接到需求任务,从 master 分支中创建功能分支,git 指令如下:

git checkout -b feature556
Switched to a new branch 'feature556'

小王在 feature556 分支上完成的功能开发工作,然后产生1次 commit,

git commit -m 'Create pop up effects'
[feature556 6104106] create pop up effects
3 files changed, 75 insertions(+)

我们再更新一下 README 自述文件,让版本差异更明显一些

git commit -m `updated md`

这时候我们看看当前分支的 git 历史记录,输入 git log --online -all 可以看到全部分支的历史线:

f2c9c7f (HEAD -> feature556) updated md
6104106 create pop up effects
a1ec682 (origin/main, origin/HEAD, main) import dio
c5848ff update this readme
8abff90 update this readme

直接看下图可能会更好理解一些

功能完成后自然要上线,我们把代码合并,完成上线动作,代码如下

git checkout master
git merge feautre556
Updating a1ec682..38348cc
Fast-forward
....... | 2+++
1 file changed, 2 insertions(+)

如果你注意上面的文字的话,你会发现 git 帮你自动执行了 Fast-forward 操作,那么什么是 Fast-forward

Fast-forward 是指 Master 合并 Feature 时候发现 Master 当前节点一直和 Feature 的根节点相同,没有发生改变,那么 Master 快速移动头指针到 Feature 的位置,所以 Fast-forward 并不会发生真正的合并,只是通过移动指针造成合并的假象,这也体现 git 设计的巧妙之处。合并后的分支指针如下:

通常功能分支(feature556) 合并 master 后会被删除,通过下图可以看到,通过 Fast-forward 模式产生的合并可以产生干净并且线性的历史记录

再说说什么是 non-Fast-forward

刚说了会产生 Fast-forward 的情况,现在再说说什么情况会产生 non-Fast-forward,通常,当合并的分支跟 master 不存在共同祖先节点的时候,这时候在 merge 的时候 git 默认无法使用 Fast-forward 模式,

我们先看看下图的模型:

可以看到 master 分支已经比 feature001 快了2个版本,master 已经没办法通过移动头指针来完成 Fast-forward,所以在 master 合并 feature001 的时候就不得不做出真正的合并,真正的合并会让 git 多做很多工作,具体合并的动作如下:

  • 找出 master 和 feature001 的公共祖先,节点 c1,c6, c3 三个节点的版本 (如果有冲突需要处理)
  • 创建新的节点 c7,并且将三个版本的差异合并到 c7,并且创建 commit
  • 将 master 和 HEAD 指针移动到 c7

补充:大家在 git log 看到很多类似:Merge branch 'feature001' into master 的 commit 就是 non-Fast-forward 产生的。

执行完以上动作,最终分支流程图如下:

如何手动设置合并模式 ?

先简单介绍一下 git merge 的三个合并参数模式:

  • -ff 自动合并模式:当合并的分支为当前分支的后代的,那么会自动执行 --ff (Fast-forward) 模式,如果不匹配则执行 --no-ff(non-Fast-forward) 合并模式
  • --no-ff 非 Fast-forward 模式:在任何情况下都会创建新的 commit 进行多方合并(及时被合并的分支为自己的直接后代)
  • --ff-onlu Fast-forward 模式:只会按照 Fast-forward 模式进行合并,如果不符合条件(并非当前分支的直接后代),则会拒绝合并请求并且推出

以下是关于 --ff, --no-ff, --ff-only 三种模式的官方说明(使用 git merge --helo 即可查看):

Specifies how a merge is handled when the merged-in history is already a descendant of the current history. --ff is the default unless merging an annotated (and possibly signed) tag that is not stored in its natural place in the refs/tags/ hierarchy, in which case --no-ff is assumed.

With --ff, when possible resolve the merge as a fast-forward (only update the branch pointer to match the merged branch; do not create a merge commit). When not possible (when the merged-in history is not a descendant of the current history), create a merge commit.

With --no-ff, create a merge commit in all cases, even when the merge could instead be resolved as a fast-forward.

With --ff-only, resolve the merge as a fast-forward when possible. When not possible, refuse to merge and exit with a non-zero status.

总结:

三种 merge 模式没有好坏和优劣之分,只有根据你团队的需求和实际情况选择合适的合并模式才是最优解,那么应该怎么选择呢? 我给出以下推荐:

  • 如果你是小型团队,并且追求干净线性 git 历史记录,那么我推荐使用 git merge --ff-only 方式保持主线模式开发是一种不错的选择
  • 如果你团队不大不小,并且也不追求线性的 git 历史记录,要体现相对真实的 merge 记录,那么默认的 git --ff 比较合适
  • 如果你是大型团队,并且要严格监控每个功能分支的合并情况,那么使用 --no-ff 禁用 Fast-forward 是一个不错的选择

git merge --ff/--no-ff/--ff-only 三种选项参数的区别的更多相关文章

  1. Java语言----三种循环语句的区别

    ------- android培训.java培训.期待与您交流! ---------- 第一种:for循环 循环结构for语句的格式:       for(初始化表达式;条件表达式;循环后的操作表达式 ...

  2. png、jpg、gif三种图片格式的区别

    png.jpg.gif三种图片格式的区别   2014-06-17 为什么想整理这方面的类容,我觉得就像油画家要了解他的颜料和画布.雕塑家要了解他的石材一样,作为网页设计师也应该对图片格式的特性有一定 ...

  3. VMware 三种网络模式的区别

    VMware 三种网络模式的区别 VMware 三种网络模式的区别 我们首先说一下VMware的几个虚拟设备 VMnet0:用于虚拟桥接网络下的虚拟交换机 VMnet1:用于虚拟Host-Only网络 ...

  4. JavaScript:学习笔记(7)——VAR、LET、CONST三种变量声明的区别

    JavaScript:学习笔记(7)——VAR.LET.CONST三种变量声明的区别 ES2015(ES6)带来了许多闪亮的新功能,自2017年以来,许多JavaScript开发人员已经熟悉并开始使用 ...

  5. 转:VMware中三种网络连接的区别

    转自:http://www.cnblogs.com/rainman/archive/2013/05/06/3063925.html VMware中三种网络连接的区别   1.概述 2.bridged( ...

  6. (转)VMware虚拟机三种网络模式的区别及配置方法;

    我的一点实际经验理解桥接和NAT 桥接是虚拟机完全作为一个独立的地址接在局域网中,NAT是虚拟机依赖宿主主机地址转换的一种方式 例子我的虚拟机如果用桥接模式,连接外部网站如百度时会提示此pc没有装公司 ...

  7. 内存分配---FF、BF、WF三种算法

    动态分区分配是根据进程的实际需要,动态的为之分配内存空间.而在实现可变分区分配时,将涉及到分区分配中 所用的数据结构.分区分配算法和分区的分配与内存回收的过程. 分区分配中的数据结构:(1)描述空闲块 ...

  8. VMware的三种网络连接方式区别

    关于VMware的三种网络连接方式,NAT,Bridged,Host-Only ,在刚接触的时候通常会遇到主机Ping不通虚拟机而虚拟机能Ping得通主机:主机与虚拟机互不相通等等网络问题.本文就这三 ...

  9. nodejs Express 4.x req.body req.query req.params 三种获取参数的方法

    第一种情况:http://localhost:3000/1,我们可以用req.params.(应该是跟路由有关,待) 第二种情况:http://localhost:3000/?id=1,用req.qu ...

随机推荐

  1. JS常用数值验证

    1.正整数验证 正整数是大于0的整数. function validateInteger(val) { return Number.isInteger(val) && val > ...

  2. LayUI之数据表格扩展

    1.点击一行 选中 以下代码需要在表格渲染完成时加载. 1)当单击表格行时,把单选按钮设为选中状态 //当单击表格行时,把单选按钮设为选中状态 $(document).on("click&q ...

  3. Springboot项目架构设计

    导航 前言 流水线 架构的艺术 项目架构 理解阿里应用分层架构 superblog项目架构 结语 参考 本节是<Spring Boot 实战纪实>的第7篇,感谢您的阅读,预计阅读时长3mi ...

  4. DCL之单例模式

    所谓的DCL 就是 Double Check Lock,即双重锁定检查,在了解DCL在单例模式中如何应用之前,我们先了解一下单例模式.单例模式通常分为"饿汉"和"懒汉&q ...

  5. 从零开始搞后台管理系统(2)——shin-server

      shin 的读音是[ʃɪn],谐音就是行,寓意可行的后端系统服务,shin-server 的特点是: 站在巨人的肩膀上,依托KOA2.bunyan.Sequelize等优秀的框架和库所搭建的定制化 ...

  6. Android中Context样式分析

    目录 1.样式定义以及使用 1.1.默认样式 1.2.样式定义及使用 1.3.当前样式下attr属性的获取 1.4.属性集合的定义与获取 2.Activity中Theme的初始化流程 2.1.系统调用 ...

  7. 解决appium点击软键盘上的搜索按钮

    在执行appium自动化测试的时候,需要点击软件盘上的搜索按钮. 具体操作步骤如下: 前提:需要事先安装搜狗输入法 1.唤醒软件盘,可以封装到一个类里,用到的时候随时调用. import os#调起s ...

  8. 太上老君的炼丹炉之分布式 Quorum NWR

    分布式系列文章: 1.用三国杀讲分布式算法,舒适了吧? 2.用太极拳讲分布式理论,真舒服! 3.诸葛亮 VS 庞统,拿下 Paxos 共识算法 4.用动图讲解分布式 Raft 5.韩信大招:一致性哈希 ...

  9. 选择 FreeBSD 而不是 Linux 的技术性原因4

    Linux 二进制兼容性 FreeBSD 提供了与 Linux 的二进制兼容.这使得用户可以在 FreeBSD 系统上安装和运行许多 Linux 二进制文件, 而无需首先修改二进制文件.在某些特定情况 ...

  10. Java高并发编程基础三大利器之CountDownLatch

    引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...