Mercurial > hg
changeset 46448:1a7d12c82057
diff: add experimental support for "merge diffs"
The way this works is it re-runs the merge and "stores" conflicts, and then
diffs against the conflicted result. In a normal merge, you should only see
diffs against conflicted regions or in cases where there was a semantic
conflict but not a textual one. This makes it easier to detect "evil merges"
that contain substantial new work embedded in the merge commit.
Differential Revision: https://phab.mercurial-scm.org/D8504
author | Augie Fackler <augie@google.com> |
---|---|
date | Thu, 07 May 2020 16:50:26 -0400 |
parents | 0cb1b02228a6 |
children | 62a0b5daa15f |
files | mercurial/commands.py tests/test-completion.t tests/test-diff-change.t |
diffstat | 3 files changed, 135 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/commands.py Mon Feb 01 12:55:31 2021 +0100 +++ b/mercurial/commands.py Thu May 07 16:50:26 2020 -0400 @@ -29,6 +29,7 @@ bundlecaches, changegroup, cmdutil, + context as contextmod, copies, debugcommands as debugcommandsmod, destutil, @@ -2464,6 +2465,16 @@ (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'merge', + False, + _( + b'show difference between auto-merge and committed ' + b'merge for merge commits (EXPERIMENTAL)' + ), + _(b'REV'), + ), ] + diffopts + diffopts2 @@ -2544,13 +2555,31 @@ to_rev = opts.get(b'to') stat = opts.get(b'stat') reverse = opts.get(b'reverse') + diffmerge = opts.get(b'merge') cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change']) cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change']) if change: repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn') ctx2 = scmutil.revsingle(repo, change, None) - ctx1 = ctx2.p1() + if diffmerge and ctx2.p2().node() != nullid: + pctx1 = ctx2.p1() + pctx2 = ctx2.p2() + wctx = contextmod.overlayworkingctx(repo) + wctx.setbase(pctx1) + with ui.configoverride( + { + ( + b'ui', + b'forcemerge', + ): b'internal:merge3-lie-about-conflicts', + }, + b'diff --merge', + ): + mergemod.merge(pctx2, wc=wctx) + ctx1 = wctx + else: + ctx1 = ctx2.p1() elif from_rev or to_rev: repo = scmutil.unhidehashlikerevs( repo, [from_rev] + [to_rev], b'nowarn'
--- a/tests/test-completion.t Mon Feb 01 12:55:31 2021 +0100 +++ b/tests/test-completion.t Thu May 07 16:50:26 2020 -0400 @@ -336,7 +336,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, 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
--- a/tests/test-diff-change.t Mon Feb 01 12:55:31 2021 +0100 +++ b/tests/test-diff-change.t Thu May 07 16:50:26 2020 -0400 @@ -194,4 +194,108 @@ 9 10 +merge diff should show only manual edits to a merge: + + $ hg diff --merge -c 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 -c 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 + +Set up a conflict. + $ hg co ".^" + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ sed -e 's,^8$,z,' file.txt > file.txt.tmp + $ mv file.txt.tmp file.txt + $ hg ci -m 'conflicting edit: 8 to z' + created new head + $ echo "this file is new in p1 of the merge" > new-file-p1.txt + $ hg ci -Am 'new file' new-file-p1.txt + $ hg log -r . --template 'p1 will be rev {rev}\n' + p1 will be rev 9 + $ hg co 5 + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo "this file is new in p2 of the merge" > new-file-p2.txt + $ hg ci -Am 'new file' new-file-p2.txt + created new head + $ hg log -r . --template 'p2 will be rev {rev}\n' + p2 will be rev 10 + $ hg co -- 9 + 2 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg merge -r 10 + merging file.txt + warning: conflicts while merging file.txt! (edit, then use 'hg resolve --mark') + 1 files updated, 0 files merged, 0 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon + [1] + $ hg revert file.txt -r . + $ hg resolve -ma + (no more unresolved files) + $ hg commit -m 'merge conflicted edit' +Without --merge, it's a diff against p1 + $ hg diff --no-merge -c 11 + diff -r fd1f17c90d7c -r 5010caab09f6 new-file-p2.txt + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/new-file-p2.txt Thu Jan 01 00:00:00 1970 +0000 + @@ -0,0 +1,1 @@ + +this file is new in p2 of the merge +With --merge, it's a diff against the conflicted content. + $ hg diff --merge -c 11 + merging file.txt + diff -r 5010caab09f6 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,12 +6,6 @@ + 5 + 6 + 7 + -<<<<<<< local: fd1f17c90d7c - test: new file + z + -||||||| base + -8 + -======= + -y + ->>>>>>> other: d9e7de69eac3 - test: new file + 9 + 10 + +There must _NOT_ be a .hg/merge directory leftover. + $ test ! -d .hg/merge +(No output is expected) $ cd ..