# HG changeset patch # User Patrick Mezard # Date 2012-02-13 16:22:35 # Node ID 0e0060bf2f440d5cc33e5f36d99868a5380debd4 # Parent b0c7525f826df69b51568b41718593e9fb0f5b74 patch: fuzz more aggressively to match patch(1) behaviour The previous code was assuming a default context of 3 lines. When fuzzing, it would take this value in account to reduce the amount of removed line from hunks top or bottom. For instance, if a hunk has only 2 lines of bottom context, fuzzing with fuzz=1 would do nothing and with fuzz=2 it would remove one of those lines. A hunk with one line of bottom context could not be fuzzed at all. patch(1) has apparently no such restrictions and takes the fuzz level at face value. - test-import.t: fuzz/offset changes at the beginning of file are explained by the new fuzzing behaviour and match patch(1) ones. Patching locations are different but those of my patch(1) do not make a lot of sense right now (patched output are the same) - test-import-bypass.t: more agressive fuzzing makes a patching supposed to fail because of context, succeed. Change the diff to avoid this. - test-mq-merge.t: more agressive fuzzing would allow the merged patch to apply with fuzz, but fortunately we disallow this behaviour. The new output is kept. I have not enough experience with patch(1) fuzzing to know whether aligning our implementation on it is a good or bad idea. Until now, it has been the implementation reference. For instance, "qpush" tolerates fuzz (test-mq-merge.t runs the special case of pushing merge revisions where fuzzing is forbidden). diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -973,7 +973,7 @@ class hunk(object): # this removes context lines from the top and bottom of list 'l'. It # checks the hunk to make sure only context lines are removed, and then # returns a new shortened list of lines. - fuzz = min(fuzz, len(old)-1) + fuzz = min(fuzz, len(old)) if fuzz: top = 0 bot = 0 @@ -991,18 +991,8 @@ class hunk(object): else: break - # top and bot now count context in the hunk - # adjust them if either one is short - context = max(top, bot, 3) - if bot < context: - bot = max(0, fuzz - (context - bot)) - else: - bot = min(fuzz, bot) - if top < context: - top = max(0, fuzz - (context - top)) - else: - top = min(fuzz, top) - + bot = min(fuzz, bot) + top = min(fuzz, top) return old[top:len(old)-bot], new[top:len(new)-bot], top return old, new, 0 diff --git a/tests/test-import-bypass.t b/tests/test-import-bypass.t --- a/tests/test-import-bypass.t +++ b/tests/test-import-bypass.t @@ -111,7 +111,15 @@ Test unsupported combinations Test commit editor - $ hg diff -c 1 > ../test.diff + $ cat > ../test.diff < diff -r 07f494440405 -r 4e322f7ce8e3 a + > --- a/a Thu Jan 01 00:00:00 1970 +0000 + > +++ b/a Thu Jan 01 00:00:00 1970 +0000 + > @@ -1,1 +1,2 @@ + > -a + > +b + > +c + > EOF $ HGEDITOR=cat hg import --bypass ../test.diff applying ../test.diff @@ -138,7 +146,7 @@ Test patch.eol is handled $ hg --config patch.eol=auto import -d '0 0' -m 'test patch.eol' --bypass ../test.diff applying ../test.diff $ shortlog - o 3:d7805b4d2cb3 test 0 0 - default - test patch.eol + o 3:c606edafba99 test 0 0 - default - test patch.eol | @ 2:872023de769d test 0 0 - default - makeacrlf | diff --git a/tests/test-import.t b/tests/test-import.t --- a/tests/test-import.t +++ b/tests/test-import.t @@ -445,7 +445,7 @@ Test fuzziness (ambiguous patch location $ hg import --no-commit -v fuzzy-tip.patch applying fuzzy-tip.patch patching file a - Hunk #1 succeeded at 1 with fuzz 2 (offset -2 lines). + Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines). applied to working directory $ hg revert -a reverting a @@ -462,7 +462,7 @@ test fuzziness with eol=auto $ hg --config patch.eol=auto import --no-commit -v fuzzy-tip.patch applying fuzzy-tip.patch patching file a - Hunk #1 succeeded at 1 with fuzz 2 (offset -2 lines). + Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines). applied to working directory $ cd .. @@ -1029,6 +1029,19 @@ Test corner case involving fuzz and skew > +line > EOF + $ cat > 04-middle-of-file-completely-fuzzed.diff < diff --git a/a b/a + > --- a/a + > +++ b/a + > @@ -1,1 +1,1 @@ + > -2 + > +add some skew + > @@ -2,2 +2,3 @@ + > not matching, should fuzz + > ... a bit + > +line + > EOF + $ cat > a < 1 > 2 @@ -1071,4 +1084,14 @@ Test corner case involving fuzz and skew 3 4 line + applying 04-middle-of-file-completely-fuzzed.diff + patching file a + Hunk #1 succeeded at 2 (offset 1 lines). + Hunk #2 succeeded at 5 with fuzz 2 (offset 1 lines). + applied to working directory + 1 + add some skew + 3 + 4 + line diff --git a/tests/test-mq-merge.t b/tests/test-mq-merge.t --- a/tests/test-mq-merge.t +++ b/tests/test-mq-merge.t @@ -125,12 +125,10 @@ Merge: merging with queue at: $TESTTMP/t2/.hg/refqueue (glob) applying patcha patching file a - Hunk #1 FAILED at 0 - 1 out of 1 hunks FAILED -- saving rejects to file a.rej - patch failed, unable to continue (try -v) - patch failed, rejects left in working dir + Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines). + fuzz found when applying patch, stopping patch didn't work out, merging patcha - 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved 0 files updated, 2 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) applying patcha2