GIT 中的重复合并。它如何计算差异?

2024-05-12

我一直在做一项研究,试图了解 GIT 合并是如何工作的。我知道有几种合并类型,如递归、章鱼等。我发现解析/递归是最常用的。并且递归合并仅在存在多个共同祖先/基础时才有用。

但是,我找不到从分支重复合并到主节点时使用哪种算法(或者如何计算祖先)。

一个简单的例子。让我们创建一个包含 1 个文件“A”的空项目:

A

然后创建另一个文件“B”并提交给master

A
B

然后我创建一个分支第一个版本其中只有 1 个文件“A”并创建另一个文件“C”。所以我的分支看起来像这样:

A
C

然后我决定将我的分支更改合并到 master 中,我得到:

A
B
C

然后我决定回到我的分支机构并从那里继续我的工作。我创建另一个文件“D”

A
C
D

现在我想将我的更改从分支合并回主干。祖先是怎么计算的?

A visual example: Repetitive merge

如果我采用祖先“AC”,则应该说“B”也是新添加的,因为它不存在于两个版本:分支和祖先。

如果我取祖先“ABC”,则应该说“B”被删除,因为 B 存在于两个版本:主版本和祖先版本。

这两个选项看起来都不正确。我试图通过使用具有合并解释功能的“Plastic SCM”来解决这个问题。如图所示,祖先/基础被用作版本“AC”,但是它仍然正确计算了添加了多少文件(只有 1 个而不是 2 个)。


总结评论并解决所提出的问题......

寻找合并基地

  1. Git 使用一种算法来计算一对提交的合并基础,该算法用于查找有向无环图的最低公共祖先。精确的算法没有在任何地方被描述,并且可能会改变,只要新的算法产生正确的结果。也可以看看在有向无环图中找到最低共同祖先的算法? https://stackoverflow.com/q/14865081/1256452

    可能有多个 LCA。在这种情况下,-s resolve合并策略选择其中之一。你无法控制它选择哪一个。这-s recursive合并策略运行git merge在他们身上,一次两个,就好像通过以下内容:

    commits=$(git merge-base --all $left $right)
    if len($commits) > 1
        a=$commits[0]
        for i in range(1, len(commits))
            b=$commits[i]
            a=$(git-merge-recursively-inner $a $b)
        rof
        commits=($a)
    fi
    

    (以伪代码形式)。请注意,内部递归合并本身可能会找到多个合并基;如果是,则使用此算法来合并它们。

    最终结果是一次提交,$commits[0]。这是合并基础。

  2. 无论如何,现在我们有了一个单一的合并基础提交——来自仅找到一个 LCA 的 LCA 查找算法,或者通过合并递归合并来自 LCA 查找算法的多个合并基础,或者通过合并-解决方法只是从列表中选择一个提交——我们可以看看如何git merge-(recursive|resolve)实际上合并文件。它必须运行两个内部git diff操作,每个操作都打开重命名检测器。

差异和文件身份/重命名检测

A 文件差异引擎比较两个文件。我们将一个文件放在左侧,另一个文件放在右侧。当两个文件匹配时,差异没有说明任何内容。当两个文件不同时,差异引擎(取决于它的好坏)会提出一些我们可以应用的更改,以使左侧的内容与右侧文件的内容匹配。

区分一对commits,Git 将一个放在左边,一个放在右边。然后它必须配对files在这两个提交中。 Git 可以在启用或不启用重命名检测器的情况下执行此操作。

当没有重命名检测器时,图片非常清晰。当且仅当左侧和右侧的文件具有相同的内容时,它们才是“同一文件”name。添加重命名检测器识别(标记为“相同”)差异左侧和右侧的某些文件,即使names已改变。

Git 现有的重命名检测器正在进行一些更改以使其变得更好。这里不需要确切的细节:我们需要知道的是,它会说某些文件被重命名,“相同”的文件也是如此,即使它们具有不同的名称。其他文件自动成为“相同”文件,因为它们具有相同的名称。

对于每个配对文件,差异引擎会生成一组更改,使左侧文件变成右侧文件。重命名检测器生成需要首先执行的重命名操作。文件是new右边的被称为added,以及左侧提交中存在但右侧提交中不存在的文件将被删除。

因此,提交对的差异导致:

  • 要重命名的文件(从旧名称到新名称)
  • 要添加的文件
  • 要删除的文件

根据需要,加上两次提交中存在的文件的一些更改集。

合并,给定合并基础

给定一个合并基础提交,解析和递归都以相同的方式进行:

  • 比较合并基础HEAD,启用重命名检测。这些都是our变化。
  • 将合并基础与其他提交进行比较,并启用重命名检测。这些都是their变化。
  • 合并更改。

“组合”需要解决单个文件中的高级更改(例如重命名、添加和删除)和低级更改。将应用组合更改的文件是来自合并基地。这保证了结果在所有情况下都有效。

例如,假设we重命名一个文件并they修改了我们重命名的文件。合并后的变化实际上表明,最后,将文件base.ext重命名为head.ext;同时,更改base.ext的第17行。因此,我们将更改第 17 行,并重命名该文件,捕获这两个操作。

高级操作可能会发生冲突!例如,如果我们重命名一个文件而他们删除它,那就是高级冲突。如果我们和他们都重命名文件,则会发生冲突,除非我们都选择相同的最终名称。如果我们和他们都删除一个文件,这与显而易见的结果结合得很好。

低水平的变化也可能发生冲突。如果我们和他们都以不同的方式修改同一行,或者如果我们的更改和他们的更改在任一边缘“接触”,就会发生冲突。例如,如果我们替换第 9 行和第 10 行(在第 8 行之后删除 2 行并在第 8 行之后插入 2 行),并且它们替换第 11 行和第 12 行,则我们的更改是相邻的。出于一般谨慎,称此为冲突。

当然,如果我们和他们能够same更改为same原来的台词,不冲突。 Git 只是获取这些更改的一份副本。

扩展选项-Xours or -Xtheirs通过选择一方(我们的或他们的)来解决低级冲突,而忽略另一方。这仅适用于低级别冲突。从逻辑上讲,它也可以适用于高层冲突,但事实并非如此。

结合我们和他们的所有更改后,Git 将应用combined对在中找到的快照进行的更改合并基地犯罪。如果没有冲突,生成的文件可以自动提交。这是这些合并的默认操作;使用--no-commit抑制此默认提交。

当 merge-recursive 使用内部合并进行合并基础提交时,它会强制提交结果即使存在合并冲突。您无法看到它对这些冲突做了什么,除非合并库中显示的任何内容your(外部)合并也有冲突。 (在这种情况下,文件的基于合并的副本在索引槽 1 中可用。另外,如果您设置merge.conflictStyle to diff3,冲突文件的每个工作树副本都将显示合并库中的文本,并带有冲突标记。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GIT 中的重复合并。它如何计算差异? 的相关文章

  • Neo4j 中合并和创建唯一之间的区别

    我试图找出合并和创建唯一之间的区别 我知道这些功能 合并 如果不存在模式 我可以创建节点 MERGE n name X RETURN n 这将创建具有属性名称的节点 n 空节点 m 和关系 RELATED MERGE n name X RE
  • Git 择优挑选然后 rebase

    当我在 git 中挑选樱桃后进行 rebase 时 有一些我不明白的事情 有人可以告诉我发生了什么事吗 场景是这样的 我正在主分支和主题分支上工作 如下所示 该主题有两次提交 C D topic A B master 我的主题分支有问题 所
  • 为什么MERGE语句的目标表不允许启用规则?

    我们有一个使用以下 SQL 更新数据库的过程 IF NOT EXISTS SELECT FROM Target Table WHERE Target Table ID BEGIN INSERT END ELSE BEGIN UPDATE E
  • Git 存储库损坏(标头检查不正确;松散对象已损坏)

    昨天晚上我在写提交消息时遇到了电源故障 当我重新启动机器时 我无法完成提交 我跑了git reset 添加回更改的文件 然后再次尝试 得到 git commit error inflate data stream error incorre
  • GitLab 是否通过 git-annex 或其他方式支持大文件?

    我运行一个 GitLab 实例 并希望允许我的用户上传几乎任何大小的文件 众所周知 git 在处理大文件方面仍然存在问题 我知道通过将文件存储在其他地方并仅对元数据进行版本控制来规避此问题的方法 例如git annex git media
  • 尝试编译 git 但在 linux 中找不到 libcurl

    我想编译支持 http https 的 git 我有 ls usr include curl curlbuild h curl h curlrules h curlver h easy h mprintf h multi h stdchea
  • 撤消 git pull,如何将存储库恢复到旧状态

    有什么方法可以恢复或撤消 git pull 以便我的源 存储库将恢复到执行 git pull 之前的旧状态 我想这样做是因为它合并了一些我不想这样做的文件 但只合并了其他剩余的文件 那么 我想找回这些文件 可以吗 编辑 我想撤消 git m
  • 编辑 git patch 给出“您编辑的块不适用”

    我正在交互地添加一个文件 git add template panels panel reports php p diff git a template panels panel reports php b template panels
  • 从 git 中提取特定的提交/文件

    我在 git 存储库中进行了两次提交 并将它们推送到我的 git 服务器 两个提交是 在第一次提交中文件 A 被提交 在第二次提交中 文件 B 被提交 现在在另一台开发服务器上 我只想从 git 服务器中提取第一个提交或文件 A 这个怎么做
  • 如何正确处理git中仅本地使用的文件?

    我想重新排序 git commits 中更改文件的输出 因此我创建了一个名为submodule orderfile并配置diff orderFile https git scm com docs git config指向该文件 现在出现了很
  • 将 git 存储库拆分为压缩的公共和初始私有

    我想在 Github 上开源一个项目 有相当多的提交 超过 2k 我会将它们压缩成一个 初始提交 以便从一个干净的代码库开始并隐藏一些历史内容 问题是 是否有可能 保留一个包含所有初始提交的私有存储库 其中会有一些秘密密钥 travis c
  • GIT Rebase 协作的分支?

    阅读本文后 重新设置基点以收集从主分支到我的功能分支的更改是有意义的 Git 工作流程以及 rebase 与合并问题 https stackoverflow com questions 457927 git workflow and reb
  • git:键不包含节

    我使用的是 Git 版本 1 8 4 2 When I press tab to auto complete any command it prints the error below and it also completes the c
  • 用于跟踪远程分支的 Git 子模块

    我正在尝试使用 git 子模块将 10 多个存储库聚合到一个结构中 以便于开发 它应该克隆模块并签出分支 相反 模块以分离头模式检出 git clone email protected cdn cgi l email protection
  • 为什么 git-cherry pick 没有说要提交什么?

    我对以下问题进行了很多搜索 但无法获得任何实质性信息 我创建了一个临时分支 202116 并尝试对 gerrit 202116 进行挑选 并收到以下消息 为什么我无法挑选此提交以及为什么会收到此错误 lt gt git fetch ssh
  • 用于维护项目扩展分支的 Git 工作流程?

    我们在 GitHub 上分叉了一个 OSS 项目 并向其添加一些自定义扩展 我们希望将我们所做的一些更改发送回原始项目 错误修复等 但其他更改是原始项目维护者目前不感兴趣的功能扩展 我正在尝试找出管理这种情况的最佳工作流程 我希望我们的主分
  • Git - 致命:无法获取当前工作目录?

    When I git clone从回购协议中 我得到 fatal Could not get current working directory No such file or directory 我该怎么办 我检查了服务器并发现 git文
  • 无法重新索引 magento 1.7.0.2 卡在“处理”上

    我的 magento 索引中有九分之七停留在 处理 状态 我需要重新索引它们才能正确显示我的网站 我通过 ftp 访问我的 var locks 并删除其中的两个文件 但是当我刷新索引页时 它们只是重新出现 index process 3 l
  • 如何在 git 中仅获取唯一的提交

    我想获取所有分支中唯一提交的列表 但是如果有人在分支中使用 rebase 则会提交松散的父项 如何解决这个问题呢 如何获取进行独特更改的提交列表 I use git log oneline graph cherry pick left ri
  • 你遇到过哪些 git 陷阱?

    我遇到的最糟糕的情况是 git 子模块 我在 github 上有一个项目的子模块 该项目无人维护 我想提交补丁 但无法提交 所以我分叉了 现在子模块指向原始库 而我需要它指向 fork 因此 我删除了旧的子模块 并将其替换为同一提交中新项目

随机推荐

  • 将 copyfromrecordset 写入范围

    我有以下 vba 它从单元格 C10 开始读取 MCO 直到其为空 并将从 SQL 数据库获取机器数量 解密和升级机器数量 这工作正常 但我在获取相应行中的数据时遇到问题 目前它总是将数据写入 D10 因为我已经对其进行了硬编码 但我不确定
  • JPA EntityManager createQuery() 与 createNamedQuery() 和 createNativeQuery()

    谁能解释一下 JPA 的以下方法之间的区别实体管理器 createQuery createNamedQuery createNativeQuery 并告诉我在什么情况下我们应该使用哪种方法 创建查询方法用于创建动态查询 这些查询是直接在应用
  • IntelliJ 无法识别 JPA 静态元模型

    我使用 JHipster 生成应用程序 并使用 Gradle 作为构建工具 当我创建实体时 我添加了过滤支持 这会生成 JPA 静态元模型 但 IntelliJ 无法识别元模型 我已经在 IntelliJ 上启用了注释处理器设置 但它似乎不
  • BASH 脚本编译多个 C++ 文件 - OpenCV

    请参见在C 和OpenCV中调用其他文件中的函数 https stackoverflow com questions 24442836 call functions in other files in c and opencv 对于最初的问
  • 如何用if条件编写ini文件

    我想编写一个带有 if else 条件的 ini 文件 我用 python 中的 ConfigParser 解析它 如何在ini文件中使用if和else语句 如果我明白你在问什么 您可能想要做的是这样的 在 INI 文件中设置条件值 sec
  • Kendo ASP.NET MVC 帮助器 Grid 泛型类

    我有以下困境 我正在尝试在部分视图内创建一个 Kendo UI 网格 该网格将与不同类型的对象一起使用 并且可以支持删除或创建等操作 该对象看起来像这样 public class GridViewModel public Type Obje
  • 使用复选框清除表单

    我正在尝试使用复选框来清除表单 但我不希望重置来清除复选框本身 我使用的代码如下
  • 如何在 Yii 中设置 returnUrl 值

    我正在使用 Yii 我遇到的问题是Yii app gt user gt returnUrl 它总是让我回到index php page 由于我不知道用户从哪个页面访问了当前页面 如何将其值设置为请求当前页面的页面 您可以使用Yii app
  • 将字符定义为单词边界

    我已经定义了 字符在乳胶模式下充当单词组成部分 我对结果非常满意 唯一困扰我的是像这样的序列 alpha beta被视为单个单词 当然 这是预期的行为 有没有办法让 emacs 将特定字符解释为单词 starter 这样 它将始终被视为其后
  • “rake db:seed”和 rake db:fixtures:load 之间有什么区别

    我是 Ruby 和 Rails 的新手 对某些事情感到好奇 在两个不同的教程中 我看到他们使用不同的方法用基本测试信息填充数据库 一种方法是使用 rake db seed 从包含示例数据的文本文件中提取数据 另一个使用 rake db fi
  • PromQL:查询警报是否被静音

    我已成功消除了当前已关闭节点的警报 并且在我们有时间物理替换它之前会持续一段时间 虽然我认为沉默会阻止警报在 Slack 通道中重新出现 但我也想在我们在 Prometheus 之上运行的 Grafana 仪表板上删除它 这是对 grafa
  • 使用 Apache Async HTTP Client 从 InputStream 构造多部分请求

    我正在尝试通过 apache async http 客户端发送多部分请求 但是得到了org apache http ContentTooLongException Content length is unknown error 我确实理解为
  • svn diff 如何仅显示更改的行

    当我使用 svn diff en lua 时 我得到以下结果 num Amount all All class Quality own Have own Have2 paper Specs piece Shard not enough no
  • 如何在 BEGIN 块之外正确声明哈希?

    考虑这个简单的程序 您能解释一下为什么在取消注释前两行后输出会有所不同吗 我的哈希发生了什么use strict 如何修复程序以供使用use strict echo e key1 nkey2 nkey3 perl lne use stric
  • 在我的 django 代码中获取 KeyError

    我对 Django 和 Python 都很陌生 所以如果我显得很烦人 请原谅我 我只是被误导了 错误代码 http i gyazo com 68d88cabf536b129dc37cde6c3ae319c png http i gyazo
  • 如何在 C++ 中比较两个向量

    这是我的代码 include
  • 如何反转字符串中的单词但将标点符号保留在正确的位置? [复制]

    这个问题在这里已经有答案了 我编写了以下代码来反转输入字符串 Scanner s new Scanner System in System out println Please enter a sentence String sentenc
  • 复制列中的所有单元格[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我有一张表 有 200 行 行间有一
  • 如何在 Linux 主机上的 docker 容器中挂载目录 [重复]

    这个问题在这里已经有答案了 我想将一个目录从 docker 容器挂载到本地文件系统 该目录是网站根目录 我需要能够使用任何编辑器在本地计算机上编辑它 我知道我可以跑docker run v local path container path
  • GIT 中的重复合并。它如何计算差异?

    我一直在做一项研究 试图了解 GIT 合并是如何工作的 我知道有几种合并类型 如递归 章鱼等 我发现解析 递归是最常用的 并且递归合并仅在存在多个共同祖先 基础时才有用 但是 我找不到从分支重复合并到主节点时使用哪种算法 或者如何计算祖先