我们有数百个存储库,并定期从上游接收补丁。作业应用这些补丁 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 --reject
和 git 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/