git-apply失败,如何进行故障排除/修复?

42

我目前正在对一个(github)存储库的PR进行代码样式检查,并希望向提交者提供补丁,以便他们可以轻松地修复代码样式问题。为此,我会拉取他们的PR,运行我们的uncrustify脚本来修复任何样式错误,并想要创建一个他们可以轻松应用的 .patch 文件。然而,它在某些文件上始终出现问题。

我使用的是git版本1.7.10.4,其中包括core.autocrlf=inputcore.filemode=false

$ git checkout pr-branch
$ git log -1 (shows: commit dbb8d3f)
$ git status (nothing to commit, working directory clean)
$ <run the code styler script, which modifies some files>
$ git diff > ../style.patch (so the patch file lands outside the repo)
$ git reset --hard HEAD (to simulate the situation at the submitter's end)
$ git log -1 (shows: commit dbb8d3f)
$ git status (nothing to commit, working directory clean, so we are where we started)
$ git apply ../style.patch
error: patch failed: somefile.cpp:195
error: somefile.cpp: patch does not apply (same output using the --check option)

这仅适用于某些文件,而不是全部文件。我不知道如何进行故障排除,即如何让git告诉我出错的具体位置 - 它只告诉我一个巨大的hunk#。

到目前为止我尝试过以下方法(但都没有成功):

  1. apply --reverse, apply --whitespace=nowarn
  2. 使用diff HEAD代替单独的diff
  3. 创建一个虚拟提交(提交不会有问题!),使用format-patch,删除虚拟提交,使用git-amgit-apply打补丁,有或没有加上-3
  4. 将补丁文件放在本地目录中,而不是在上一级(纯属瞎猜)
  5. 查看git-diff、-apply、-format-patch、-am的手册是否有有用的信息
  6. 使用Linux的patch命令打补丁
  7. ....

我不知道diff可能出了什么问题。空格应该只会发出警告,对吧?无论如何,我不想忽略它们,因为这是一个显然涉及空格的样式修复。

我该如何修复/诊断这个问题,甚至找出它究竟在哪里失败?如果我发布一个有问题的文件的diff,是否会有所帮助?令我困惑的是提交没有问题,但从提交创建的补丁却有问题?

在苦苦挣扎了数个小时后,我的知识已经耗尽了...


8
运行git apply --reject命令以查看被拒绝的更改。 - aragaer
已经尝试过了...这只会显示整个失败的代码块(在那个案例中大约有2-300行),所以并不是很有用。 - Christoph
不,这只是文本文件中的样式更改,没有重命名。Franci的--index选项似乎已经解决了这个问题。 - Christoph
1
我曾经遇到过同样的问题。对我有帮助的是 --whitespace=fix,但我仍然不明白为什么,因为我只是创建了补丁,没有手动编辑它。 - torvin
我来到这里,是因为与 CRLF 字符有关的不同原因。这个答案 帮助我解决了它。 - Ricardo
显示剩余4条评论
3个回答

42
更新:
你可以使用git apply -v来查看更详细的有关操作的信息,git apply --check用于仅验证操作,或者git apply --index用于重建本地索引文件。
根据您的评论,似乎您的本地索引已损坏,所以index解决了这个问题。
我将保留我的原始回答和评论,主要是为了让人们了解发生了什么情况,因为我怀疑其他人会根据问题描述得出相同的初步结论。
------
最可能的情况是diff没有任何问题。相反,看一下目标git存储库。虽然你正在执行git reset --hard HEAD,但并没有保证那个其他存储库上的HEAD与你的相同。
在目标repo上执行git log,查看顶部的提交。它与您生成差异的提交相同吗?很可能不是。向下查看历史记录,并检查是否存在您需要的提交。如果存在,则目标repo在您的前面,您需要返回,执行git pull(或git rebase)并生成一个新的差异。如果不存在,则目标repo落后于您的,您需要在目标repo上执行git pull(或git rebase)将其升级到最新状态。
请记住,如果您有其他人提交到您的“主”repo(您和目标repo都在从中拉取),则可能需要git pull两个repo,以使它们达到相当近期的公共提交。

从您的描述中并不清楚两个“HEAD”是否指向相同的提交。我猜想它们并不是,但如果您已经检查过它们并且它们确实是相同的,那么差异确实存在问题。 - Franci Penov
另外,尝试使用 git apply -v 命令,或者尝试使用 --check-index 选项进行调试。 - Franci Penov
2
真的吗?如果我只是git-checkout,更改一些文件,然后git-reset --hard HEAD而没有在中间提交,HEAD怎么可能不同呢? 我已经尝试过这些选项了,但我得到的只是一些关于空格的东西。我会再试一次并发布更多信息。 - Christoph
"git checkout" 和 "git reset" 都是本地仓库命令。除非目标仓库是源仓库的上游仓库(在这种情况下,我期望您执行 git push 而不是做差异),否则在检出之前必须执行 git pullgit rebase - Franci Penov
还是你正在执行 git checkout origin/pr-branch - Franci Penov
显示剩余6条评论

13

尝试根据您的补丁文件进行检查 - 例如:

git apply --reject mypatch.patch

这将展示您任何差异-以下是它可能看起来的示例:

error: patch failed: <filename>:<linenumber>
error: while searching for :
    cout << "}" << endl; // example of a line in your patch

1
@YasinOkumuş 你说得对,这并没有解决问题,但它跳过了错误并应用了其余部分并解释了原因,所以基本上这就是你所能要求的 :) - Mosh Feu

1

在这种情况下,如果您已经尝试了以下所有选项:

  1. 调查文件中潜在的非打印/不可见字符
  2. 使用dos2unix进行转换
  3. 更改git配置以调整处理行结尾的方式,例如:
git config --global core.autocrlf input

在这种情况下,另一个罪恶的根源可能是你的IDE。
例如,像PHPStorm这样的JetBrains IDE有以下选项:

enter image description here

今天我花了超过4个小时来解决一个奇怪的补丁问题,最终出现了以下错误:
git apply < my.git.patch --verbose
...
error: patch failed: plugins/some/file.php:74

我意识到我的编辑器可能是罪魁祸首(我不确定这是否是默认行为)。我使用PHPStorm检查补丁文件时,它会悄无声息地从补丁文件中删除一个单独的空格,而实际上目标文件确实存在该空格需要被修补。这非常隐蔽,我最终将“保存时删除尾随空格”的选项设置为“无”以避免再次发生此类问题。同时请注意,平台相关的差异,如底层文件系统的大小写敏感性(例如MacOS/Linux),也可能是问题的根源。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接