2

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

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

例如,补丁中的块是

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

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

但是在应用的文件中,块是

@@ -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
4

1 回答 1

3

--3wayTL;DR:如果可能的话,你确实想要。

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

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

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

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

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

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

  • 如果存在有效的索引行但您的存储库中没有该对象,Git 将无法构建该文件的基本副本及其副本。

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

于 2021-12-01T13:37:43.647 回答