101

I am trying to move several commits from one project to the second, similar one, using git.

So I created a patch, containing 5 commits:

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

Then move the patch to second project's folder and wants to apply the patch:

git am changes.patch 

...but it gives me error:

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".

So I opened the index.php, but nothing changed there. I assume some >>>>>>> marks etc., like when resolving merge conflict, but no conflict was marked in the file. git status gave me also empty list of changed files (only changes.patch was there). So I run git am --continue, but another error appears:

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". 

I am using Windows 7 and newest git version "1.9.4.msysgit.1"

P.S. After few hours of googling, I found few solutions, but nothing works for me:


git am -3 changes.patch 

gives strange "sha1 information" error:

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

gives first error as above: "error: patch failed: index.php:17", but no conflict marks in index.php was added.

nanuqcz
  • 1,376
  • 3
  • 16
  • 19
  • 6
    I have been struggling with this, too. But in some cases it was caused by files (from e.g. WIndows sources) committed while CRLF was in line endings. It seems that git does not like CRLF line endings, despite a config feature like eol.crlf. Sample link regarding cr/lf issues: http://stackoverflow.com/questions/1510798/trying-to-fix-line-endings-with-git-filter-branch-but-having-no-luck/ – Rob May 29 '15 at 15:49
  • 1
    Great. Just had to convert the line endings of a patch I received into "Unix"-style and after that it worked. That earns an upvote. – user2808624 Feb 26 '16 at 16:30

9 Answers9

124

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).

torek
  • 448,244
  • 59
  • 642
  • 775
  • 15
    Thank you for great answer. The `git am changes.patch --reject` is best for me, because it offers alternative to "conflict marks" (found in .rej files). Then `git add`, `git am --continue` and everything works fine :-) – nanuqcz Sep 15 '14 at 13:01
  • 3
    yes, thank you. it was surprising to me that `git am` didn't (like `patch`) try to apply the changes that *do* apply. – Steven R. Loomis Dec 29 '15 at 22:14
  • It seems bizarre that git is sometimes unable to apply patches produced by itself. I am using `git log --pretty=email --patch-with-stat --reverse -- filename` – Ed Randall May 22 '17 at 11:23
  • 3
    @EdRandall: if you use `git am` or `git apply -3` *and* you have the base version of the file in your repository, Git should be able to do a three-way merge (with potential merge conflicts, of course). Note that you may need the person who sends the patch to use `--full-index` when generating the patch. – torek May 22 '17 at 12:46
  • So many inconsistencies between git commands. `--reject` should've been enabled by default, just like the merge or rebase commands. – jaques-sam Aug 12 '20 at 07:25
  • 1
    @DrumM: merge and rebase always have the base file, so they don't actually *need* the equivalent of `--reject` since they always have the equivalent of `-3`. That said, I am used to the GNU-style `patch` command, so I too usually prefer the `--reject` mode, but I can see arguments either way. – torek Aug 12 '20 at 14:41
  • Your explanation about 3-way merges seems to be... not exactly clear. The way I understand it, with a 3-way merge `git` is able to determine the base commit (common ancestor) and figure out what changes were made in both branches. As long as they were made in nonadjacent lines, it would apply. With patches and another (not a clone) repository that's not an option. Technically `git am` could be more liberal in applying patches, but it has less information to makes decisions, and that goes in line with the `patch` behavior... – x-yuri Jun 18 '22 at 07:27
  • ...You can find an example in [my answer](https://stackoverflow.com/a/72667422/52499) (the gist). – x-yuri Jun 18 '22 at 07:27
  • @x-yuri: when merging *commits* (`git merge ` etc), Git uses the *commit graph* to determine the merge base. This provides the base version for the three-way merge process. But when using `git am` or `git apply` to apply a `git format-patch` style *diff*, Git uses the `index` lines in the diff to find the base version. It uses the hash ID on the left to find a blob in your repository; that blob is assumed to be the base *file* for the three-way merge, with the `--ours` file being the file to be patched, and the `--theirs` file being the result of patching the base file with the patch. – torek Jun 19 '22 at 07:05
  • Because of the above process, the hash ID Git finds in the `index` line *must* locate a blob object in your own repository. The patch *must* apply cleanly to that blob object (producing the `--theirs` version of the file). The index line *must exist*. Your example in your answer shows a patch that does not contain an `index` line: it's missing the "a little more" part. – torek Jun 19 '22 at 07:06
  • Don't take me wrong. There was no diff in my answer :) No proper diff. I just wanted to show the changes. When I tried to apply the patch it had the index line, as you can see in the gist. Additionally, my [further experiments](https://gist.github.com/x-yuri/9907d5b9cbf29e84d510902a776741df) show that you can [make `git` do a 3-way merge](https://stackoverflow.com/a/72797965/52499) by having both histories in the repository where you apply the patch, and passing `-3` to `am`. As a result it either applies in cases where it otherwise wouldn't, or you end up with the conflict markers. – x-yuri Jun 29 '22 at 08:26
  • @x-yuri: Right - but that's exactly what I said above: either there's a Git patch, which is a diff plus a little bit more, or there's a non-Git patch, which is a diff that lacks that little bit more. If the little bit more—the `index` line—exists, *and* you have the object in question, Git can reconstruct the full set of 3 inputs and do a 3-way merge. If not, it can't. That's it. – torek Jun 29 '22 at 08:30
  • There seems to be a little more to your answer. In the second gist I have a repository with 2 commits (A with `1,2,3`, B with `1,2,33`), and a repository with one commit (C with `11,2,3`). (The numbers are lines in the file separated by a comma.) `format-patch` creates a patch that "points" (the index line) to A. As a result, it can find out what the file looked like in A, but the contents in C differs from the contents in A (A != C), and still it applies. I mostly think about the wording in your answer. It introduces details, but does this in a way that leaves at least me with questions... – x-yuri Jun 29 '22 at 09:15
  • ...Also, the index line refers not to commit hashes (as one might think), but probably to hashes of the file contents. – x-yuri Jun 29 '22 at 09:15
  • @x-yuri: Yes, the hash ID in each index line is a blob hash (not a commit hash). I'm not sure why that matters to you here. – torek Jun 30 '22 at 08:50
  • Don't take me wrong, I'd like to improve your answer. The issue with it is that it tries to explain why a 3-way merge is able to do a better job. But fails, in my view. More on it [here](https://gist.github.com/x-yuri/57d08f6afb10a89856d6e6a62abe30d4). – x-yuri Jul 02 '22 at 13:33
  • No offense, but I couldn't figure it out. So I asked on the [mailing list](https://www.spinics.net/lists/git/msg442116.html). You can see the result in [my answer](https://stackoverflow.com/a/72797965/52499). Feel free to improve your answer if you want. – x-yuri Jul 06 '22 at 00:12
  • @x-yuri: this SO question is not about *why* a 3-way merge is *more capable* than a simple patch. It is instead about *what you can do* when even `git am -3` doesn't apply. Note that if you have access to the original repository from which someone *generated* a patch, you don't need to use the patch at all! – torek Jul 06 '22 at 00:34
  • It's not exactly about what's more capable... You were trying to explain why it failed. If not... you could just omit the "little more" and "original version" parts. But you brought them up and I couldn't help but try to figure out what exactly that means. Also, I believe that more often than not knowing the reason is important to make a good decision. By the way, a good point about "if you have access to the original repository." Apparently, both the OP and I had that kind of access. But we were thinking in terms of patches, because the histories were unrelated. – x-yuri Jul 06 '22 at 03:13
  • ...And one option would be to provide less details: "For `git am` to succeed the contexts should not contradict the files to be patched. To use `git am -3` you need to have the objects in the repository. You can do `git remote add` + `git fetch`, but then you can just cherry-pick the commit." This doesn't bring up the original version and the little more. My point is that you introduced them in a way I couldn't understand. – x-yuri Jul 06 '22 at 03:21
20

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

Tatiana Racheva
  • 1,289
  • 1
  • 13
  • 31
srs
  • 2,521
  • 16
  • 16
  • 1
    The parameter `-3Way` is wrong, it's either `-3` or `--3way`. And this doesn't answer the question. – jaques-sam Aug 12 '20 at 07:30
  • 1
    It's a typo in code section. Thanks for pointing it out. If you had followed the full answer, you might have noticed that, in the text section it was mentioned --3Way in Bold. According to the question, merge conflicts were not showing after applying the patch. I had the same problem and I solved it using that command only. – srs Aug 14 '20 at 05:06
  • 1) you place `--` after `...should be:`, this already looks like a typo, I easily read over the `--` and read the code line below. 2) Just anoying that code answers don't contain the correct answers ;-) Better to present only code which is correct. 3) the typo in the original question was not causing his issue... – jaques-sam Aug 17 '20 at 12:35
  • 4
    I don't know why exactly, but the `--ignore-space-change` option was what made my patch file work. – Sky Oct 13 '20 at 11:00
  • This worked for me. In my case I still had a merge conflict, but this command setup the conflict file like normal. I was able to resolve the conflict using `git mergetool`. – esteuart Feb 17 '21 at 20:37
8

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
wulfgarpro
  • 6,666
  • 12
  • 69
  • 110
8

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.

MikeBeaton
  • 3,314
  • 4
  • 36
  • 45
5

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

Pini Cheyni
  • 5,073
  • 2
  • 40
  • 58
1

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.

x-yuri
  • 16,722
  • 15
  • 114
  • 161
0

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

Sandeep K V
  • 97
  • 2
  • 3
0

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

0

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.

x-yuri
  • 16,722
  • 15
  • 114
  • 161