changeset 52989:688665425496

diff: add a --ignore-changes-from-ancestors option This is a generalisation of the new feature from evolve but for any diff, it allow to compares changes to patches regardless of the changes introduced by ancestors, this is typically useful after rebase and graft. I am not very happy about the name, but it is still experimental, so that can be improved later. Having the ability to compare ranges of commit would probably be handy too, but this changeset focus in getting the basic case in. We have to think about the UI a bit ahead however.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Fri, 03 Feb 2023 11:01:23 +0100
parents 3ced516694ad
children 5ec596c91086
files mercurial/commands.py tests/test-completion.t tests/test-diff-patches.t
diffstat 3 files changed, 502 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commands.py	Tue Feb 18 15:33:51 2025 +0100
+++ b/mercurial/commands.py	Fri Feb 03 11:01:23 2023 +0100
@@ -27,6 +27,7 @@
     bundlecaches,
     changegroup,
     cmdutil,
+    context as contextmod,
     copies,
     debugcommands as debugcommandsmod,
     destutil,
@@ -2540,6 +2541,14 @@
         (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
         (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
         (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
+        (
+            b'',
+            b'ignore-changes-from-ancestors',
+            False,
+            _(
+                b'only compare the change made by the selected revision (EXPERIMENTAL)'
+            ),
+        ),
     ]
     + diffopts
     + diffopts2
@@ -2621,6 +2630,7 @@
     to_rev = opts.get(b'to')
     stat = opts.get(b'stat')
     reverse = opts.get(b'reverse')
+    patch_only = opts.get(b'ignore_changes_from_ancestors')
 
     cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
     cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
@@ -2638,6 +2648,30 @@
         repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
         ctx1, ctx2 = logcmdutil.revpair(repo, revs)
 
+    if patch_only and ctx1.p1() != ctx2.p1():
+        old_base = ctx1.p1()
+        new_base = ctx2.p1()
+        new_ctx = contextmod.overlayworkingctx(repo)
+        new_ctx.setbase(ctx1)
+        configoverrides = {
+            (b'ui', b'forcemerge'): b'internal:merge3-lie-about-conflicts'
+        }
+        with ui.configoverride(configoverrides, b'obslog-diff'), ui.silent():
+            mergemod._update(
+                repo,
+                new_base,
+                labels=[
+                    b'from',
+                    b'parent-of-to',
+                    b'parent-of-from',
+                ],
+                force=True,
+                branchmerge=True,
+                wc=new_ctx,
+                ancestor=old_base,
+            )
+        ctx1 = new_ctx.tomemctx(text=ctx1.description())
+
     if reverse:
         ctxleft = ctx2
         ctxright = ctx1
--- a/tests/test-completion.t	Tue Feb 18 15:33:51 2025 +0100
+++ b/tests/test-completion.t	Fri Feb 03 11:01:23 2023 +0100
@@ -358,7 +358,7 @@
   debugwhyunstable: 
   debugwireargs: three, four, five, ssh, remotecmd, insecure
   debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
-  diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
+  diff: rev, from, to, change, ignore-changes-from-ancestors, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
   export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
   files: rev, print0, include, exclude, template, subrepos
   forget: interactive, include, exclude, dry-run
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-patches.t	Fri Feb 03 11:01:23 2023 +0100
@@ -0,0 +1,467 @@
+=============================================================
+Testing comparing changeset regardless of change from parents
+=============================================================
+
+Setup
+=====
+
+Add a bunch of changes some related to each other some not.
+
+  $ hg init test-repo
+  $ cd test-repo
+  $ cat << EOF > file-a.txt
+  > one
+  > two
+  > three
+  > four
+  > five
+  > six
+  > seven
+  > eight
+  > nine
+  > ten
+  > EOF
+  $ hg add file-a.txt
+  $ hg commit -m 'commit_root'
+
+  $ sed s/two/deux/ file-a.txt > a
+  $ mv a file-a.txt
+  $ hg commit -m 'commit_A1_change'
+
+  $ sed s/five/cinq/ file-a.txt > a
+  $ mv a file-a.txt
+  $ hg commit -m 'commit_A2_change'
+
+  $ cat << EOF > file-b.txt
+  > egg
+  > salade
+  > orange
+  > EOF
+  $ hg add file-b.txt
+  $ hg commit -m 'commit_A3_change'
+
+  $ cat << EOF > file-b.txt
+  > butter
+  > egg
+  > salade
+  > orange
+  > EOF
+  $ hg commit -m 'commit_A4_change'
+
+  $ hg up 'desc("commit_root")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ sed s/two/deux/ file-a.txt > a
+  $ mv a file-a.txt
+  $ sed s/ten/dix/ file-a.txt > a
+  $ mv a file-a.txt
+  $ hg commit -m 'commit_B1_change'
+  created new head
+
+  $ sed s/five/funf/ file-a.txt > a
+  $ mv a file-a.txt
+  $ sed s/eight/acht/ file-a.txt > a
+  $ mv a file-a.txt
+  $ hg commit -m 'commit_B2_change'
+
+  $ cat << EOF > file-b.txt
+  > milk
+  > egg
+  > salade
+  > apple
+  > EOF
+  $ hg add file-b.txt
+  $ hg commit -m 'commit_B3_change'
+
+  $ cat << EOF > file-b.txt
+  > butter
+  > milk
+  > egg
+  > salade
+  > apple
+  > EOF
+  $ hg commit -m 'commit_B4_change'
+
+  $ hg log -G --patch
+  @  changeset:   8:0d6b02d59faf
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     commit_B4_change
+  |
+  |  diff -r 59c9679fd24c -r 0d6b02d59faf file-b.txt
+  |  --- a/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  |  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  |  @@ -1,3 +1,4 @@
+  |  +butter
+  |   milk
+  |   egg
+  |   salade
+  |
+  o  changeset:   7:59c9679fd24c
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     commit_B3_change
+  |
+  |  diff -r 1e73118ddc3a -r 59c9679fd24c file-b.txt
+  |  --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+  |  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  |  @@ -0,0 +1,4 @@
+  |  +milk
+  |  +egg
+  |  +salade
+  |  +apple
+  |
+  o  changeset:   6:1e73118ddc3a
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     commit_B2_change
+  |
+  |  diff -r 30a40f18d81e -r 1e73118ddc3a file-a.txt
+  |  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  |  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  |  @@ -2,9 +2,9 @@
+  |   deux
+  |   three
+  |   four
+  |  -five
+  |  +funf
+  |   six
+  |   seven
+  |  -eight
+  |  +acht
+  |   nine
+  |   dix
+  |
+  o  changeset:   5:30a40f18d81e
+  |  parent:      0:9c17110ca844
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     commit_B1_change
+  |
+  |  diff -r 9c17110ca844 -r 30a40f18d81e file-a.txt
+  |  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  |  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  |  @@ -1,5 +1,5 @@
+  |   one
+  |  -two
+  |  +deux
+  |   three
+  |   four
+  |   five
+  |  @@ -7,4 +7,4 @@
+  |   seven
+  |   eight
+  |   nine
+  |  -ten
+  |  +dix
+  |
+  | o  changeset:   4:e6f5655bdf2e
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     commit_A4_change
+  | |
+  | |  diff -r 074ad64f5cd7 -r e6f5655bdf2e file-b.txt
+  | |  --- a/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  | |  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  | |  @@ -1,3 +1,4 @@
+  | |  +butter
+  | |   egg
+  | |   salade
+  | |   orange
+  | |
+  | o  changeset:   3:074ad64f5cd7
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     commit_A3_change
+  | |
+  | |  diff -r 37c330f02452 -r 074ad64f5cd7 file-b.txt
+  | |  --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+  | |  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  | |  @@ -0,0 +1,3 @@
+  | |  +egg
+  | |  +salade
+  | |  +orange
+  | |
+  | o  changeset:   2:37c330f02452
+  | |  user:        test
+  | |  date:        Thu Jan 01 00:00:00 1970 +0000
+  | |  summary:     commit_A2_change
+  | |
+  | |  diff -r 7bcbc987bcfe -r 37c330f02452 file-a.txt
+  | |  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  | |  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  | |  @@ -2,7 +2,7 @@
+  | |   deux
+  | |   three
+  | |   four
+  | |  -five
+  | |  +cinq
+  | |   six
+  | |   seven
+  | |   eight
+  | |
+  | o  changeset:   1:7bcbc987bcfe
+  |/   user:        test
+  |    date:        Thu Jan 01 00:00:00 1970 +0000
+  |    summary:     commit_A1_change
+  |
+  |    diff -r 9c17110ca844 -r 7bcbc987bcfe file-a.txt
+  |    --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  |    +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  |    @@ -1,5 +1,5 @@
+  |     one
+  |    -two
+  |    +deux
+  |     three
+  |     four
+  |     five
+  |
+  o  changeset:   0:9c17110ca844
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     commit_root
+  
+     diff -r 000000000000 -r 9c17110ca844 file-a.txt
+     --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+     +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+     @@ -0,0 +1,10 @@
+     +one
+     +two
+     +three
+     +four
+     +five
+     +six
+     +seven
+     +eight
+     +nine
+     +ten
+  
+
+Then compare the resulting revisions:
+====================================
+
+A1 and B1 has the same parent, so the same output is expected.
+
+
+  $ hg diff --from 'desc("commit_A1_change")' --to 'desc("commit_B1_change")'
+  diff -r 7bcbc987bcfe -r 30a40f18d81e file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -7,4 +7,4 @@
+   seven
+   eight
+   nine
+  -ten
+  +dix
+  $ hg diff --from 'desc("commit_A1_change")' --to 'desc("commit_B1_change")' --ignore-changes-from-ancestors
+  diff -r 7bcbc987bcfe -r 30a40f18d81e file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -7,4 +7,4 @@
+   seven
+   eight
+   nine
+  -ten
+  +dix
+
+Skipping B1 change mean the final "ten" change is no longer part of the diff
+
+  $ hg diff --from 'desc("commit_A1_change")' --to 'desc("commit_B2_change")'
+  diff -r 7bcbc987bcfe -r 1e73118ddc3a file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -2,9 +2,9 @@
+   deux
+   three
+   four
+  -five
+  +funf
+   six
+   seven
+  -eight
+  +acht
+   nine
+  -ten
+  +dix
+  $ hg diff --from 'desc("commit_A1_change")' --to 'desc("commit_B2_change")' --ignore-changes-from-ancestors
+  diff -r 1e73118ddc3a file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -2,9 +2,9 @@
+   deux
+   three
+   four
+  -five
+  +funf
+   six
+   seven
+  -eight
+  +acht
+   nine
+   dix
+
+Skipping A1 changes means the "two" changes introduced by "B1" (but also
+present in A2 parent, A1) is back on the table.
+
+  $ hg diff --from 'desc("commit_A2_change")' --to 'desc("commit_B1_change")'
+  diff -r 37c330f02452 -r 30a40f18d81e file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -2,9 +2,9 @@
+   deux
+   three
+   four
+  -cinq
+  +five
+   six
+   seven
+   eight
+   nine
+  -ten
+  +dix
+  $ hg diff --from 'desc("commit_A2_change")' --to 'desc("commit_B1_change")' --ignore-changes-from-ancestors
+  diff -r 30a40f18d81e file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -1,10 +1,10 @@
+   one
+  -two
+  +deux
+   three
+   four
+  -cinq
+  +five
+   six
+   seven
+   eight
+   nine
+  -ten
+  +dix
+
+All changes from A1 and B1 are no longer in the picture as we compare A2 and B2
+
+  $ hg diff --from 'desc("commit_A2_change")' --to 'desc("commit_B2_change")'
+  diff -r 37c330f02452 -r 1e73118ddc3a file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -2,9 +2,9 @@
+   deux
+   three
+   four
+  -cinq
+  +funf
+   six
+   seven
+  -eight
+  +acht
+   nine
+  -ten
+  +dix
+  $ hg diff --from 'desc("commit_A2_change")' --to 'desc("commit_B2_change")' --ignore-changes-from-ancestors
+  diff -r 1e73118ddc3a file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -2,9 +2,9 @@
+   deux
+   three
+   four
+  -cinq
+  +funf
+   six
+   seven
+  -eight
+  +acht
+   nine
+   dix
+
+Similar patches
+---------------
+
+comparing A3 and B3 patches is much more terse. focusing on the change to the
+two similar patches, ignoring the rests of the changes (like comparing apples
+and oranges)
+
+  $ hg diff --from 'desc("commit_A3_change")' --to 'desc("commit_B3_change")'
+  diff -r 074ad64f5cd7 -r 59c9679fd24c file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -2,9 +2,9 @@
+   deux
+   three
+   four
+  -cinq
+  +funf
+   six
+   seven
+  -eight
+  +acht
+   nine
+  -ten
+  +dix
+  diff -r 074ad64f5cd7 -r 59c9679fd24c file-b.txt
+  --- a/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -1,3 +1,4 @@
+  +milk
+   egg
+   salade
+  -orange
+  +apple
+  $ hg diff --from 'desc("commit_A3_change")' --to 'desc("commit_B3_change")' --ignore-changes-from-ancestors
+  diff -r 59c9679fd24c file-b.txt
+  --- a/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -1,3 +1,4 @@
+  +milk
+   egg
+   salade
+  -orange
+  +apple
+
+
+Conflict handling
+-----------------
+
+Conflict should not be a big deal and its resolution should be presented to the user.
+
+  $ hg diff --from 'desc("commit_A4_change")' --to 'desc("commit_B4_change")'
+  diff -r e6f5655bdf2e -r 0d6b02d59faf file-a.txt
+  --- a/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-a.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -2,9 +2,9 @@
+   deux
+   three
+   four
+  -cinq
+  +funf
+   six
+   seven
+  -eight
+  +acht
+   nine
+  -ten
+  +dix
+  diff -r e6f5655bdf2e -r 0d6b02d59faf file-b.txt
+  --- a/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -1,4 +1,5 @@
+   butter
+  +milk
+   egg
+   salade
+  -orange
+  +apple
+  $ hg diff --from 'desc("commit_A4_change")' --to 'desc("commit_B4_change")' --ignore-changes-from-ancestors
+  diff -r 0d6b02d59faf file-b.txt
+  --- a/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file-b.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -1,9 +1,5 @@
+  -<<<<<<< from:           e6f5655bdf2e - test: commit_A4_change
+   butter
+  -||||||| parent-of-from: 074ad64f5cd7 - test: commit_A3_change
+  -=======
+   milk
+  ->>>>>>> parent-of-to:   59c9679fd24c - test: commit_B3_change
+   egg
+   salade
+   apple