git apply --reject 与 git apply --3way

标签 git git-apply

我们有数百个存储库,并定期从上游接收补丁。作业应用这些补丁 git apply --check <patch> .如果没有错误,则应用补丁 git apply <patch>并且更改已提交。如果有任何错误,补丁将标记为 conflict .然后将错误和冲突的补丁交付给我们的存储库维护人员。他们使用 git apply --reject <patch>应用补丁并解决冲突。

根据我之前的理解,git apply --reject是可靠的。然而,一位维护者报告说补丁的应用方式完全错误。一些新行被插入到意外函数中的一个 block 中,而该函数恰好具有相同的上下文。还有其他一些错误的 block 。

比如patch中的chunk是

@@ -1757,9 +1757,9 @@ def FunctionAAA()

              print('hi')
          }
        + print('hello world')
          print('good day')
          return True 

但是在应用文件中,chunk是

@@ -1927,9 +1997,9 @@ def FunctionBBB()   ---> in another function

              print('hi')
          }
        + print('hello world')
          print('good day')
          return True

维护者很可能没有注意到错位的行,这会导致构建错误或更糟糕的 stash 错误。我让维护者试试 git apply --3way <patch>尽管仍然存在冲突,但补丁已按预期应用。

我认为git apply --rejectgit apply --3way行为不同,因为它们使用不同的算法。从结果来看,我想我们需要采用 git apply --3way .但我也担心 --3way在某些情况下可能会出乎意料。

为什么 git apply --reject以看似错误的方式工作而不是将 block 视为冲突?在我们的情况下哪个更好?有没有更好的解决方案来应用补丁?谢谢。

git version 2.31.1
ubuntu 4.15.0-76-generic

最佳答案

TL;DR:如果可能的话,您确实想要--3way

这里有一些历史。 git apply 命令最初至少部分是 Larry Wall's historical patch command 的克隆,或多或少。 .此补丁命令始终在 --reject 模式下运行(请参阅文档:(POSIX)(non-POSIX))。在这种模式下运行时,它永远不会进行三向 merge 。

另一方面,补丁有缺陷:应用于上下文匹配的模糊因子允许插入指示的更改,即使上下文实际上并不匹配。 (Git 的 apply 没有模糊测试。)上下文匹配可能会出错,就像你的情况一样,找到一个类似的 looking 函数,但不是正确的函数.三路 merge 通过三个输入避免了这些问题:

  • merge 基础,或共同起点;
  • 您的文件版本;和
  • 他们的文件版本。

Git 可以使用 Git 补丁中的 Index: 行构造其中两个版本,其中包含文件基本版本的 blob 哈希 ID。 Git 只是使用散列 ID 在存储库中找到正确的 blob 对象。如果该对象存在,那就是他们在 diff 中作为“之前”副本的文件,因此 Git 可以提取该对象,完全按照它出现的方式应用补丁,并生成文件的“他们的”版本。 Git 现在可以对这三个文件进行正常的三向 merge 。

--3way 选项在两种情况下失败:

  • 如果没有给出 merge 基础版本的 Index: 行,Git 就无法知道文件的哪个副本是上下文差异中的“之前”版本。

  • 如果有一个有效的索引行,但您的存储库中没有该对象,Git 无法构建该文件的基础副本和他们的副本。

在这些情况下,唯一可用的选项是回退:尝试找到正确的上下文(并希望很多并在需要时使用 --reject)。

关于git apply --reject 与 git apply --3way,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70182303/

相关文章:

git: "branchname"和 "refs/heads/branchname"之间的区别

git - 使用 Cake Build 创建远程存储库标签

java - Jenkins上的Maven部署文件错误

git - 如何为 git 中的最后 N 次提交准备和应用多个补丁

用于交互式应用补丁的 Git 单行代码

git - 如何从 github 中的不同分支 merge

linux - Git 从部分存储库中提取?

git - 如何查看将提交的文件

Git merge repo 之外的文件内容(--no-index)