Applying a patch that adds an empty file

Mads Kiilerich mads at kiilerich.com
Thu Jul 1 15:24:06 CDT 2010


  Greg Ward wrote, On 07/01/2010 07:32 PM:
> But this seems like a bug in patch.py to me.  First, here's patch
> behaving as it should:
>
> $ cat patch1
> diff --git a/a b/a
> new file mode 100644
> --- /dev/null
> +++ b/a
> @@ -0,0 +1,1 @@
> +foo
> $ hg patch --no-commit -f patch1
> applying patch1
> $ hg patch --no-commit -f patch1
> applying patch1
> file a already exists
> 1 out of 1 hunks FAILED -- saving rejects to file a.rej
> abort: patch failed to apply
>
> That's obviously correct: apply the same patch twice and the second
> attempt fails.
>
> But if the patch is slightly different, the behaviour is completely different:
>
> $ cat patch2
> diff --git a/b b/b
> new file mode 100644
> --- /dev/null
> +++ b/b
> $ hg patch --no-commit -f patch2
> applying patch2
> $ hg patch --no-commit -f patch2
> applying patch2
>
> It gets weirder:
>
> $ echo foo>  b
> $ hg patch --no-commit -f patch2
> applying patch2
>
> That *really* should conflict.  The patch wants b to be an empty file,
> and it clearly isn't.

Patch handling is mess. Two hairy state machines trying to agree on what 
is going on.

It seems like the code can be simplified a lot without loss of 
functionality, but the requirements are unknown and the test coverage 
apparently incomplete, so there is some reluctance to change it. 
(http://selenic.com/pipermail/mercurial-devel/2010-April/020655.html)

The following patch will apparently solve this specific problem, but it 
will introduce other failures because the code is inconsistent regarding 
whether afile and bfile should contain full paths or strip the a/b 
prefixes that are mandatory in the git format.

--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -1107,6 +1107,16 @@
              emitfile = True
              state = BFILE
              hunknum = 0
+
+    if (sourcefile or state == BFILE) and not context and not 
current_hunk and emitfile:
+        x = '@@ -0,0 +0,0 @@\r\n'
+        gpatch = changed.get(bfile)
+        create = afile == '/dev/null' or gpatch and gpatch.op == 'ADD'
+        remove = bfile == '/dev/null' or gpatch and gpatch.op == 'DELETE'
+        current_hunk = hunk(x, hunknum + 1, lr, context, create, remove)
+        yield 'file', (afile, bfile, current_hunk)
+        empty = False
+
      if current_hunk:
          if current_hunk.complete():
              yield 'hunk', current_hunk

/Mads



More information about the Mercurial-devel mailing list