`git am` always fails applying patch from `git format-patch -U0`

From: Nutchanon Wetchasit <hidden>
Date: 2020-05-05 12:04:11

Hello folks,

I was rewriting a committed change in my repository via a workflow
of git-format-patch -> edit -> git-am.

The edit I wanted to make was just a one-line change in the diff,
with no line number shift, so I generated patches with no context line
(`git format-patch -U0`) to avoid subsequent patch failure
caused by context change.

But the problem was that `git-am` appeared to erroneously
reject such patches for an unclear reason...

After editing patches, hard-resetting the branch to the parent commit
of the chain; I fed the patches to `git am`, and encountered an error
that looked like this:
Applying: Removing second line
error: patch failed: text.txt:2
error: text.txt: patch does not apply
Patch failed at 0001 Removing second line
hint: Use 'git am --show-current-patch=diff' to see the failed 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".
The first thing I thought, was that I somehow messed up my patches
somewhere in the edit.

So I canceled the patching process with `git am --abort`,
hard-reset the branch again, and re-attempted running `git am`
with *unmodified* patches series;
and found that `git am` still produced the same error,
which ruled out the factor of my editing mistakes.
(Why would Git refuse a patch generated by itself?)

To be sure, I retried this on a dummy repository,
with only one non-modified zero-context patch;
and the error was still consistently reproducible.

I'm not sure what caused Git to reject such zero-context patches;
although some hints could be seen when running
`git apply --verbose` with the offending patch file.
(See step 9 in "Exact steps to reproduce" below)

GNU Patch would happily apply the same patch without any error though.

Nevertheless, this does not happen when the patch
was generated with 1 or more context lines.
So the workaround would be using `git format-patch -U1` instead,
with more risk of rejects on context change caused by editing.

-----

General steps to reproduce follows:

1. Make any disposable Git repository with two or more commits
   on `master` branch.

2. Generate a zero-context patch of the latest commit with
   `git format-patch -U0 HEAD^`

3. Remove the latest commit with `git reset --hard HEAD^`

4. Re-add the commit via the patch from step 2, with `git-am`;
   it would claim that the patch does not apply.

Compare and contrast: try the same, but change step 2 to
`git format-patch -U1` HEAD^`, and you would see that `git-am`
accept it normally.

-----

Exact steps to reproduce follows:

 1. Create an empty Git repository, with dummy user name and email:
    
    $ mkdir am-nocontext
    $ cd am-nocontext
    $ git init
    $ git config user.name "Joe Average"
    $ git config user.email "joe@example.com"
    
 2. Create a dummy 3-line text file, add it as the first commit:
    
    $ printf "One\nTwo\nThree\n" > text.txt
    $ git add text.txt
    $ git commit -m "Initial commit"
    
 3. Remove the second line from that file, make it a second commit:
    
    $ printf "2d\nwq\n" | ed text.txt
    $ git commit -am "Removing second line"
    
 4. Generate patch from the second commit, with *zero* context line:
    
    $ git format-patch -U0 HEAD^
    
 5. Back out the second commit:
    
    $ git reset --hard HEAD^
    
 6. Add back the second commit using the patch from step 4:
    
    $ git am 0001-Removing-second-line.patch
    Applying: Removing second line
    error: patch failed: text.txt:2
    error: text.txt: patch does not apply
    Patch failed at 0001 Removing second line
    hint: Use 'git am --show-current-patch=diff' to see the failed 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".
    
    ^ You would find that Git reported that patching was failed,
      when it should not be.
    
 8. Cancel the patching process:
    
    $ git am --abort
    
 9. Try re-applying the same patch to the working tree using Git:
    
    $ git apply --verbose 0001-Removing-second-line.patch
    Checking patch text.txt...
    error: while searching for:
    Two
    
    error: patch failed: text.txt:2
    error: text.txt: patch does not apply
    
    ^ You would see that somehow Git tried to take the first line
      in the hunk as a context, even when it wasn't marked as such.
    
10. Apply the same patch using GNU diffutils' `patch` program:
    
    $ patch -p 1 -i 0001-Removing-second-line.patch
    patching file text.txt
    $ git diff
    diff --git a/text.txt b/text.txt
    index 4fcefbf..3146b8f 100644
    --- a/text.txt
    +++ b/text.txt
    @@ -1,3 +1,2 @@
     One
    -Two
     Three
    
    ^ You would find that GNU Patch would apply
      the same patch correctly.

The full terminal transcript is attached as
<attachment:reproducing.log>,
which also includes intermediate informational steps,
and also displays the exact patch content produced by the process.

-----

System information follows...

   Git: 2.26.2 (source)
 Patch: GNU diffutils 2.6.1 (Debian)
System: Debian GNU/Linux 7.0 Wheezy i386
Locale: th_TH (local encoding TIS-620)

Note that this problem appears to exist for long way down to at least
Git 1.7.10.4 (the original version I found this error), if not earlier.

Please advice in case I overlooked something.

Regards,
Nutchanon Wetchasit

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help