Git am 错误: “ patch does not application”

我正在尝试使用 git 将几个提交从一个项目移动到第二个项目,类似的情况。

所以我创建了一个包含5次提交的补丁:

git format-patch 4af51 --stdout > changes.patch

然后将补丁移动到第二个项目的文件夹,并希望应用补丁:

git am changes.patch

但它给了我一个错误:

Applying: Fixed products ordering in order summary.
error: patch failed: index.php:17
error: index.php: patch does not apply
Patch failed at 0001 Fixed products ordering in order summary.
The copy of the patch that failed is found in:
c:/.../project2/.git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

所以我打开 index.php,但是没有任何改变。我假设一些 >>>>>>>标记等,像在解决合并冲突时,但没有冲突被标记在文件中。git status也给了我一个已更改文件的空列表(只有 changes.patch在那里)。所以我运行 git am --continue,但出现了另一个错误:

Applying: Fixed products ordering in order summary.
No changes - did you forget to use 'git add'?
If there is nothing left to stage, chances are that something else
already introduced the same changes; you might want to skip this patch.
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

我使用的是 Windows 7和最新的 git 版本“1.9.4. msysgit. 1”

另外,在几个小时的谷歌搜索后,我找到了一些解决方案,但没有一个对我有用:


git am -3 changes.patch

出现奇怪的“ sha1信息”错误:

Applying: Fixed products ordering in order summary.
fatal: sha1 information is lacking or useless (index.php).
Repository lacks necessary blobs to fall back on 3-way merge.
Cannot fall back to three-way merge.
Patch failed at 0001 Fixed products ordering in order summary.
The copy of the patch that failed is found in:
c:/.../project2/.git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

git am changes.patch --ignore-whitespace --no-scissors --ignore-space-change

给出了如上所示的第一个错误: “ error: patch false: index.php: 17”,但是没有在 index.php中添加冲突标记。

139549 次浏览

What is a patch?

A patch is little more (see below) than a series of instructions: "add this here", "remove that there", "change this third thing to a fourth". That's why Git tells you:

The copy of the patch that failed is found in:
c:/.../project2/.git/rebase-apply/patch

You can open that patch in your favorite viewer or editor, open the files-to-be-changed in your favorite editor, and "hand apply" the patch, using what you know (and Git does not) to figure out how "add this here" is to be done when the files-to-be-changed now look little or nothing like what they did when they were changed earlier, with those changes delivered to you as a patch.

A little more

A three-way merge introduces that "little more" information than the plain "series of instructions": it tells you what the original version of the file was as well. If your repository has the original version, your Git software, working in your repository, can compare what you did to a file, to what the patch says to do to the file.

As you saw above, if you request the three-way merge, Git can't find the "original version" in the other repository, so it can't even attempt the three-way merge. As a result you get no conflict markers, and you must do the patch-application by hand.

(There are cases where the "a little more" part is missing. The extra information is supplied by the Index: line in the patch, e.g.:

diff --git a/go.mod b/go.mod
index 1fefa60..38a3a41 100644

The second line may read, e.g.:

index 1fefa6021dcd205c1243e236d686595920d9621b..38a3a41434fda3a68ce3356092a89afca81eb614 100644

in more-complete cases. Note the two hash IDs, separated by two dots. The one on the left is the one your Git software will use, to attempt to find a file in your own repository that has the given hash ID. Applying the supplied patch to that file, which must exist, must work and must produce a file whose hash ID will be that on the right, and doing all of this gives Git all the additional information required.)

Using --reject

When you have to apply the patch by hand, it's still possible that Git can apply most of the patch for you automatically and leave only a few pieces to the entity with the ability to reason about the code (or whatever it is that needs patching). Adding --reject tells Git to do that, and leave the "inapplicable" parts of the patch in rejection files. If you use this option, you must still hand-apply each failing patch, and figure out what to do with the rejected portions.

Once you have made the required changes, you can git add the modified files and use git am --continue to tell Git to commit the changes and move on to the next patch.

What if there's nothing to do?

Since we don't have your code, I can't tell if this is the case, but sometimes, you wind up with one of the patches saying things that amount to, e.g., "fix the spelling of a word on line 42" when the spelling there was already fixed.

In this particular case, you, having looked at the patch and the current code, should say to yourself: "aha, this patch should just be skipped entirely!" That's when you use the other advice Git already printed:

If you prefer to skip this patch, run "git am --skip" instead.

If you run git am --skip, Git will skip over that patch, so that if there were five patches in the mailbox, it will end up adding just four commits, instead of five (or three instead of five if you skip twice, and so on).

git format-patch also has the -B flag.

The description in the man page leaves much to be desired, but in simple language it's the threshold format-patch will abide to before doing a total re-write of the file (by a single deletion of everything old, followed by a single insertion of everything new).

This proved very useful for me when manual editing was too cumbersome, and the source was more authoritative than my destination.

An example:

git format-patch -B10% --stdout my_tag_name > big_patch.patch
git am -3 -i < big_patch.patch

I had this error, was able to overcome it by using : patch -p1 < example.patch

I took it from here: https://www.drupal.org/node/1129120

Had several modules complain about patch does not apply. One thing I was missing out was that the branches had become stale. After the git merge master generated the patch files using git diff master BRANCH > file.patch. Going to the vanilla branch was able to apply the patch with git apply file.patch

I faced same error. I reverted the commit version while creating patch. it worked as earlier patch was in reverse way.

[mrdubey@SNF]$ git log 65f1d63 commit 65f1d6396315853f2b7070e0e6d99b116ba2b018 Author: Dubey Mritunjaykumar

Date: Tue Jan 22 12:10:50 2019 +0530

commit e377ab50081e3a8515a75a3f757d7c5c98a975c6 Author: Dubey Mritunjaykumar Date: Mon Jan 21 23:05:48 2019 +0530

Earlier commad used: git diff new_commit_id..prev_commit_id > 1 diff

Got error: patch failed: filename:40

working one: git diff prev_commit_id..latest_commit_id > 1.diff

I had the same problem. I had used

git format-patch <commit_hash>

to create the patch. My main problem was patch was failing due to some conflicts, but I could not see any merge conflict in the file content. I had used git am --3way <patch_file_path> to apply the patch.

The correct command to apply the patch should be:

git am --3way --ignore-space-change <patch_file_path>

If you execute the above command for patching, it will create a merge conflict if patch apply fails. Then you can fix the conflict in your files, like the same way merge conflicts are resolved for git merge

This kind of error can be caused by LF vs CRLF line ending mismatches, e.g. when you're looking at the patch file and you're absolutely sure it should be able to apply, but it just won't.

To test this out, if you have a patch that applies to just one file, you can try running 'unix2dos' or 'dos2unix' on just that file (try both, to see which one causes the file to change; you can get these utilities for Windows as well as Unix), then commit that change as a test commit, then try applying the patch again. If that works, that was the problem.

NB git am applies patches as LF by default (even if the patch file contains CRLF), so if you want to apply CRLF patches to CRLF files you must use git am --keep-cr, as per this answer.

With patches git is more picky compared to cherry-pick/rebase/merge conflicts. E.g. given the following file:

line 1
line 2
line 3

and the following changes (this is not a diff, it's an illustration of changes in a diff-like form):

 line 11
line 2
-line 3
+line 33

With rebase/merge there will be no conflict, with am there will. Steps to reproduce can be found here.

As such, one option would be to change the patch until it applies.

tl;dr Temporarily add the source repository (git remote add NAME ../some/path), fetch the objects (git fetch NAME), then cherry-pick the commit.

There's a difference between applying a patch and doing a 3-way merge. With a patch you have a file that you want to patch and a diff that contains changes surrounded by their contexts. If a context changes, git (or patch for that matter) can no longer apply the patch because it assumes, "As long as the context matches, that's the target lines." (It's a bit more elaborate than that, but let's keep it simple.)

Let's say you want to patch (revision A, or HEAD):

aa
b
c
d
e

with (a simplified patch):

 a
b
-c
+cc
d
e

Here git doesn't know what the file looked like before applying the patch (the file based on which the patch was created). Let's call the revision before applying the patch B, and after applying the patch C. Putting it in terms of revisions, git doesn't know what revision B of the file looked like. On one hand it could assume that before revision A you did a -> aa, and it should apply the patch. On the other hand revision B could look like this:

aa
b
c
d
e
a
b
c
d
e

Which means that before revision A you deleted the last 5 lines (a-e) and the patch should not be applied.

That's what happens when you don't pass -3 to git am. When you do pass -3 it tries to do a 3-way merge. And if it has enough information, it either succeeds, or leaves you with the context markers. So, what exactly does it need? It needs to know what the file looked like (full contents of the file) in all 3 revisions. For that git format-patch provides each file with 2 hashes: a hash of the file contents before the change (a blob hash), and another one after the change (see the index line). Now, if git am -3 can find the blobs by their hashes in your (target) repositony, it knows what the file looked like in all 3 revisions, and can do a 3-way merge.

For example, revision A (HEAD):

aa
b
c
d
e

revision B (before the patch):

a
b
c
d
e

revision C (after the patch):

a
b
cc
d
e

Knowing this it sees that you changed the first line, the patch changes the third, which can be applied w/o a conflict.

Now, how to make revisions B and C available for git? One way would be to temporarily add the source repository (a remote) where you created the patch (git remote add NAME ../some/path), and do git fetch NAME. After applying the patch (git am -3 PATCH) you can delete the remote (git remote rm NAME) if it's no longer needed. But then... you can just cherry-pick the commit.

One can apply changes w/o adding a remote, but that doesn't look too practical.

Here's a reply on the mailing list, and my experiments. Just in case.