Patchwork D8504: diff: add experimental support for "merge diffs"

login
register
mail settings
Submitter phabricator
Date May 7, 2020, 9:27 p.m.
Message ID <differential-rev-PHID-DREV-sykpnd53ndeief7rps26-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/46286/
State New
Headers show

Comments

phabricator - May 7, 2020, 9:27 p.m.
durin42 created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Still TODO before this is "done" (so probably don't push this patch yet):
  
  - Test showing how conflicting edits behave (I suspect this is broken)
  - Test showing how added files behave (this is misbehaving for me, eg `hg diff --merge 26ce8e751503 --stat` should be pretty empty but is large)
  - Figure out why this is leaving a dangling .hg/merge directory around
  
  Publishing the patch now as motivation for the preceding patches, and
  in case someone has feedback on the approach.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8504

AFFECTED FILES
  mercurial/commands.py
  tests/test-completion.t
  tests/test-diff-change.t

CHANGE DETAILS




To: durin42, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/tests/test-diff-change.t b/tests/test-diff-change.t
--- a/tests/test-diff-change.t
+++ b/tests/test-diff-change.t
@@ -141,4 +141,48 @@ 
    9
    10
 
+merge diff should show only manual edits to a merge:
+
+  $ hg diff --merge 6
+  merging file.txt
+(no diff output is expected here)
+
+Construct an "evil merge" that does something other than just the merge.
+
+  $ hg co ".^"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge -r 5
+  merging file.txt
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ echo 11 >> file.txt
+  $ hg ci -m 'merge 8 to y with manual edit of 11' # 7
+  created new head
+  $ hg diff -c 7
+  diff -r 273b50f17c6d -r 8ad85e839ba7 file.txt
+  --- a/file.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -6,6 +6,7 @@
+   5
+   6
+   7
+  -8
+  +y
+   9
+   10
+  +11
+Contrast with the `hg diff -c 7` version above: only the manual edit shows
+up, making it easy to identify changes someone is otherwise trying to sneak
+into a merge.
+  $ hg diff --merge 7
+  merging file.txt
+  diff -r 8ad85e839ba7 file.txt
+  --- a/file.txt	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/file.txt	Thu Jan 01 00:00:00 1970 +0000
+  @@ -9,3 +9,4 @@
+   y
+   9
+   10
+  +11
+
   $ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -325,7 +325,7 @@ 
   debugwhyunstable: 
   debugwireargs: three, four, five, ssh, remotecmd, insecure
   debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
-  diff: rev, 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, change, merge, 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
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -29,6 +29,7 @@ 
     bundle2,
     changegroup,
     cmdutil,
+    context as contextmod,
     copies,
     debugcommands as debugcommandsmod,
     destutil,
@@ -2406,6 +2407,15 @@ 
     [
         (b'r', b'rev', [], _(b'revision'), _(b'REV')),
         (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
+        (
+            b'',
+            b'merge',
+            b'',
+            _(
+                b'show difference between auto-merge and committed merge (EXPERIMENTAL)'
+            ),
+            _(b'REV'),
+        ),
     ]
     + diffopts
     + diffopts2
@@ -2480,10 +2490,28 @@ 
     change = opts.get(b'change')
     stat = opts.get(b'stat')
     reverse = opts.get(b'reverse')
+    mergerev = opts.get(b'merge')
 
     if revs and change:
         msg = _(b'cannot specify --rev and --change at the same time')
         raise error.Abort(msg)
+    elif mergerev and (revs or change):
+        msg = _(
+            b'cannot specify --merge and --rev or --change at the same time'
+        )
+        raise error.Abort(msg)
+    elif mergerev:
+        repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
+        mctx = scmutil.revsingle(repo, mergerev, None)
+        if mctx.p2().node() == nullid:
+            raise error.Abort(_(b'--merge requires a merge commit'))
+        ctx1 = mctx.p1()
+        ctx2 = mctx.p2()
+        wctx = contextmod.overlayworkingctx(repo)
+        wctx.setbase(ctx1)
+        stats = mergemod.merge(ctx2, wc=wctx)
+        ctx1 = wctx
+        ctx2 = mctx
     elif change:
         repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
         ctx2 = scmutil.revsingle(repo, change, None)