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