git 申请 --reject 与 git 申请 --3way

git apply --reject vs git apply --3way

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

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

例如补丁中的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

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

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

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

git version 2.31.1
ubuntu 4.15.0-76-generic

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

这里有一些历史。 git apply 命令最初至少部分是 Larry Wall's historical patch command. This patch command always operates in --reject mode (see the documentation: (POSIX), (non-POSIX)) 的或多或少的克隆。当运行处于这种模式时,它从不进行三向合并。

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

  • 合并基地,或共同起点;
  • 您的 文件版本;和
  • 他们的 文件版本。

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

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

  • 如果没有 Index: 行给出合并基础版本,Git 就无法知道文件的哪个副本是上下文差异

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

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