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) 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/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 ..