gitgit-patchgit-am

Why does git apply and am fail?


I have a patch file which contains a single line change. Running git am fails with the message:

error: patch failed: Pages/Index.cshtml.cs:15
error: Pages/Index.cshtml.cs: patch does not apply
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Applying: restrict index page to internal users
Patch failed at 0001 restrict index page to internal users
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".

The target file does have a couple of extra lines above the changed line. Is this failing because git cannot determine where the single line change? If so, does this mean that the target file and source file need to be essentially the same?

Running git apply with the same patch produced this message:

error: patch failed: Pages/Index.cshtml.cs:15
error: Pages/Index.cshtml.cs: patch does not apply

I believe this is basically the same message, just friendly (or, at least, less verbose.)

Am I attempting something which patches are not meant for? Namely, applying a change from one repository to another which are not possessing file content equivalence.

I did find this post but when using the same solution all I get is no change and a simple .rej file output.


Solution

  • The target file does have a couple of extra lines above the changed line. Is this failing because git cannot determine where the single line change?

    Yes, that is the case. Git checks not only the specific change (add this, delete that) but also the context in which the change occurs. If the context does not match, the patch does not apply.

    Using -3 or --3way can help: the idea behind this option is that if the patch was made to a version of the file that you do have, in your Git repository, Git can extract that version of the file, compare that version to the current version, see what has changed in your copy of the file, and combine (as in, git merge style operations) your changes and their changes. Pictorially, imagine this:

    ...--o--o--B--o--o--o--C   <-- your current commit and copy of the file
                \
                 D   <-- the commit from which the patch was generated
    

    Commit B is the base version, which your commit C and their commit D shared. The patch changes the base version of the file. Your commit C has a different version of the same file, but by comparing D vs B—i.e., what's in the patch—and comparing C vs B at the same time, Git may be able to figure out, on its own, how to apply the patch after all.

    The trick here is to understand where Git comes up with the file from commit B. The answer to that is in the index line, if there is one, in the patch. The index gives Git the information needed to find the copy of the file that would be in commit B—provided, of course, that you actually have that copy of the file in your repository.