首页 > 解决方案 > 当 /usr/bin/patch 成功时,为什么 git apply 失败?

问题描述

标签: gitdiffpatch

解决方案


(一个执行摘要 TL;DR:补丁不是提交;格式补丁用于提交。旧patch命令是关于补丁的,git apply介于转换工具和只是一部分之间git am。)

这里有几个关键问题:

  • 从您的patch输出来看,补丁的某些部分似乎已经应用,而有些则没有。该patch命令将询问是否对每个大块使用反转选项,但git apply要求反转适用于每个大块,或应用大块。所以它不会做补丁在这里做的事情。

  • 鉴于某些补丁因此不会应用,git apply 需要选择--reject应用其余补丁。该patch命令假定等效(总是愿意创建一个.rej文件)。(在您的情况下,让补丁取消应用一半的差异并应用另一半来解决这个问题。)

  • patch假设默认模糊因子为 2;您的几个补丁适用于模糊。patch模糊因子是允许忽略的上下文行数。默认情况下,git apply要求所有上下文行匹配:这相当于-F 0in patchgit patch您可以在使用-C参数时获得模糊因子的效果。

所以,如果你跑了git apply -C 1 --reject,这个补丁很可能会被拒绝。patch除非您对每次逆转说不,否则结果将与您得到的结果不匹配。

(旁注:--recount实际上是用于编辑的补丁,而不是用于上下文搜索调整。)

关于格式补丁

我也发生了一个类似的重要问题:生成的补丁format-patch甚至没有应用patch,所以我做了git diff master..BRANCH > adhoc.patch并且它有效!

这既不足为奇(因为它发生了),也值得密切关注(当它确实发生时),因为这意味着你没有得到你希望得到的东西。仔细看看,看看是什么然后用它来决定如何得到你想要的——不管最后可能是什么。

所做的是git format-patch将一些普通的提交——即一些单父提交——或一些这样的提交系列,转换为包含足够信息来重构每个提交的电子邮件文本文件。1 (该git am命令进行重建。稍后重建这些提交,例如,从邮箱格式输入文件,通常会保留原始作者,但会产生不同的提交者。)

什么git diff任意两个任意提交2比较它们并生成一个补丁,如果应用该补丁,则将左侧提交给出的快照转换为右侧提交给出的快照。在这里,两个提交分别是 的master和 的BRANCH。双点语法 ,git diff master..BRANCH逐渐被弃用,取而代之的是git diff master BRANCH语法,但两者的含义完全相同。

请注意,可能没有一组提交会由单个git format-patch命令发出,该命令会将master快照提示转换为快照提示BRANCH。例如,假设我们有以下提交:

          I--J--K   <-- master
         /
...--G--H
         \
          L--M--N   <-- BRANCH

git format-patch命令可以一次性格式化L-M-N补丁(生成三个可通过电子邮件发送的重建文件),但这些需要应用于提交H以重现匹配LMN. 或者,git format-patch可以一次性格式化I-J-K补丁;但是这些也需要应用于 commit H,而不是 commit K,以便产生 commit K

如果您拥有的是与 commit 匹配的快照(不是 Git 存储库,只是一个快照)K,您可以将三个补丁转换HK反转它们以在本地获取另外三个快照,它们相当于J, I, 然后H; 然后,您可以在正常的向前方向上添加产生 、 和 finally 的L三个M补丁N

但是,正如我们从上图中所看到的,没有任何提交可以让我们一步一步从 commitK到 commit N。为了获得一个让我们一步到位的补丁,我们必须直接区分提交。这样的补丁不能重新创建之前的任何提交:如果我们只有与 相关的快照,并且我们应用此补丁,我们将获得与 相关的快照,但我们不知道是什么样的,例如。KNKNH

如果某个补丁(或某些格式补丁输出)的接收者具有适当的 Git 存储库,他们可以应用格式补丁输出,只要他们具有所需的基本提交,并获得等效的提交(尽管具有不同的提交者信息)。例如,这对于仔细审查特别有帮助。但是,如果接收者没有必要的提交——甚至可能根本没有 Git 存储库——那么format-patch结果就没有那么有用了,无论如何,一个简单的一次性git diff补丁可能是最好的。详细信息因收件人而异。


1--stdout format-patch 命令还可以生成适合直接馈送到的单个输出流 ( ) git am,但现在它更适用于生成一个包含可发送电子邮件的文件的目录,适合馈送到git send-email. 这适用于各种 Linux 组、Git 项目本身等使用的电子邮件补丁方法。

2git diff命令可以采用其他不一定是提交的输入,但在这种情况下 ( master..BRANCH),我们获得了比较两个提交的模式。


推荐阅读