当前位置: 首页 > news >正文

git 的合并原理(递归三路合并算法)

如果 git 只是一行行比较,然后把不同的行报成冲突,那么你在合并的时候可能会遇到大量的冲突;这显然不是一个好的版本管理工具。

本文介绍 git 合并分支的原理。


本文内容

      • git 的冲突表示
      • 三路合并
      • 递归三路合并
      • 快进式合并
        • 参考资料

git 的冲突表示

例如我们有这样的三个提交 a、b、c。a、b 是在 master 上的其他修改,c 是我自己基于 master 上的 a 的修改。

现在,将 master 分支合并到我自己的 t/walterlv 分支:

git 提交树

a 提交:

Console.WriteLine("Hello World!");

b 提交:

Console.WriteLine("Hello Master!");

c 提交:

Console.WriteLine("Hello Walterlv!");

于是现在将 c 提交合并到 master 的时候就会出现冲突。冲突的表示会是这样:

<<<<<<< HEAD
Console.WriteLine("Hello Walterlv!");
=======
Console.WriteLine("Hello Master!");
>>>>>>> master

<<<<<<< 表示冲突开头,>>>>>>> 表示冲突结尾,======= 分隔冲突的不同修改。上面是 HEAD,也就是在合并之前的工作目录上的最近提交;下面是合并进来的分支,通常是来自其他人的修改。

三路合并

加入上面的 b 提交修改的是其他文件。然后依然按照前面的方式进行合并。

当出现冲突时,如果你只能看到不同的两行,那么你根本不知道究竟应该如何修改的。就像下面这样:

<<<<<<< HEAD
Console.WriteLine("Hello Walterlv!");
=======
Console.WriteLine("Hello World!");
>>>>>>> master

只看这点你怎么知道两行应该采用哪一行?这是二路合并算法带来的问题。在此算法下,你的每次拉取代码可能都会带来大量的冲突;这显然是不能接受的。

三路合并算法会找到合并的这两个提交的共同祖先。在这里也就是 a 提交。master 的此文件对 a 没有修改,而当前分支 t/walterlv 对此文件有修改,于是就会应用此分支的修改。

当然,前一节的问题依然会冲突,因为两个分支相对于共同的祖先节点 a 对同一个文件都有修改。

递归三路合并

从上面我们可以看到三路合并解决了二路合并中对于相同行不知道用哪一个的问题。不过实际的 git 提交树会更加复杂,就像下图那样纵横交错:

纵横交错的 git 提交树

相比于本文一开始,我们只是新增了两个提交而已,现在 f 提交是我们正在合并的提交。

如果现在找 e 和 d 的共同祖先,你会发现并不唯一,b 和 c 都是。那么此时怎么合并呢?

  1. git 会首先将 b 和 c 合并成一个虚拟的提交 x,这个 x 当作 e 和 d 的共同祖先。
  2. 而要合并 b 和 c,也需要进行同样的操作,即找到一个共同的祖先 a。

我们这里的 a、b、c 只是个比较简单的例子,实际上提交树往往更加复杂,这就需要不断重复以上操作以便找到一个真实存在的共同祖先,而这个操作是递归的。这便是“递归三路合并”的含义。

这是 git 合并时默认采用的策略。

快进式合并

git 还有非常简单的快进式(Fast-Forward)合并。快进式合并要求合并的两个分支(或提交)必须是祖孙/父子关系。例如上面的 e 和 d 并不满足此关系,所以无法进行快进式合并。

在上面的例子合并出了 f 之后,如果将 t/walterlv 合并到 master,那么就可以使用快进式合并。这时,直接将 master 分支的 HEAD 指向 f 提交即完成了合并。当然,可以生成也可以不生成新的 g 提交,但内容与 f 的内容完全一样。


参考资料

  • version control - Why is a 3-way merge advantageous over a 2-way merge? - Stack Overflow
  • Guiffy SureMerge - A Trustworthy 3-Way Merge
  • git merge - Which version of the git file will be finally used: LOCAL, BASE or REMOTE? - Stack Overflow
  • Git merge strategy options & examples - Atlassian Git Tutorial
  • git-merge-base (1) - Find as good common ancestors as possible for a merge

我的博客会首发于 https://walterlv.com/,而 CSDN 和博客园仅从其中摘选发布,而且一旦发布了就不再更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • git 合并策略
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • 使用一句 git 命令将仓库的改动推送到所有的远端
  • 将 svn 仓库迁移到 git 仓库
  • 使用 Visual Studio 调试多进程的程序
  • 如何更精准地设置 C# / .NET Core 项目的输出路径?(包括添加和删除各种前后缀)
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新)
  • 为 WPF 程序添加 Windows 跳转列表的支持
  • 在 Windows 系统上降低 UAC 权限运行程序(从管理员权限降权到普通用户权限)
  • 专栏素材
  • Visual Studio 如何能够不进行编译就调试 .NET/C# 项目(用于解决大项目编译缓慢的问题)
  • 仅反射加载(ReflectionOnlyLoadFrom)的 .NET 程序集,如何反射获取它的 Attribute 元数据呢?
  • 全局或为单独的项目添加自定义的 NuGet 源
  • __proto__ 和 prototype的关系
  • 07.Android之多媒体问题
  • Flannel解读
  • Go 语言编译器的 //go: 详解
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • IP路由与转发
  • Javascript基础之Array数组API
  • jquery cookie
  • Python 基础起步 (十) 什么叫函数?
  • Sequelize 中文文档 v4 - Getting started - 入门
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 巧用 TypeScript (一)
  • 使用docker-compose进行多节点部署
  • 微信支付JSAPI,实测!终极方案
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • puppet连载22:define用法
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (九)信息融合方式简介
  • (原)Matlab的svmtrain和svmclassify
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .NET 依赖注入和配置系统
  • .net6Api后台+uniapp导出Excel
  • .netcore 获取appsettings
  • .vollhavhelp-V-XXXXXXXX勒索病毒的最新威胁:如何恢复您的数据?
  • /etc/sudoer文件配置简析
  • @javax.ws.rs Webservice注解
  • @RequestParam,@RequestBody和@PathVariable 区别
  • [ C++ ] STL---string类的使用指南
  • [20140403]查询是否产生日志
  • [Android] 修改设备访问权限
  • [BJDCTF2020]The mystery of ip1
  • [BZOJ4566][HAOI2016]找相同字符(SAM)
  • [C#]OpenCvSharp使用帧差法或者三帧差法检测移动物体
  • [C++] Windows中字符串函数的种类
  • [Flutter]WindowsPlatform上运行遇到的问题总结
  • [go] 策略模式
  • [JS]Math.random()随机数的二三事