Author: wolever


(work in progress - see status)

Show only the changes introduced by a merge.

Use case: you are reviewing code, and you would like to see only the changes that were introduced by a merge, but *not* the changes leading up to the merge.

This extension does not currently work with Mercurial >=1.9


$ hg mdiff
--- a/changed_in_merge # changed to "in a" in branch 'a'
--- b/changed_in_merge # changed to "in b" in branch 'b'
+++ c/changed_in_merge # changed to "merged" in the merge
- in b
 -in a
--- a/resolved # same as above, except changed to "in a"
+++ c/resolved # to resolve the merge conflict
- in b
+ in a
--- /dev/null
--- /dev/null
+++ c/added_in_merge # file added in the merge
++added in merge


Imagine a DAG that looks like this (arrows point from child to parent):

Note that:

Therefore, the merge diff should contain exactly: AP2-P1MAP1-P2M (where "-" is the "set difference" operation).


The mergediff algorithm has been implemented and appears to function correctly.

The implementation is currently suboptimal (it uses more time and memory than is strictly necessary)… But this should only be a problem for "really big" merges.


The algorithm which compares hunks (ie, to perform AP2-P1M) only considers the source file, destination file and context diff. Notably, it does //not// consider the diff's location in the destination file.

I've done this to help cope with situations where, for example, changes are made above a hunk in one branch, which causes their offset to be different in the "parent to merge" diff than it is in the "base to parent" diff.

Here's an example, from the testing repository:

$ hg diff -r a:merge
diff --git a/top_bottom b/top_bottom
--- a/top_bottom
+++ b/top_bottom
@@ -10,3 +10,4 @@ <<< note: line 10
 unchanged line 7
 unchanged line 8
 unchanged line 9
+bottom change
$ hg diff -r 0:b
diff --git a/top_bottom b/top_bottom
--- a/top_bottom
+++ b/top_bottom
@@ -9,3 +9,4 @@ <<< note: line 9
 unchanged line 7
 unchanged line 8
 unchanged line 9
+bottom change

This could potentially lead to changes being incorrectly ignored (eg, if a change which should not be ignored has the same context diff as a change which should be ignored)… But I'm not sure what the best way to fix it will be.


The code is available at:

I've tried to roughly emulate git's combined diff format. There are, however, some notable differences:

Format notes


Q: What's wrong with hg diff -r <merge>?
A: In short, diff -r <merge> will show changes from one of the branches. For example, taking the diff of a clean merge will show changes, but showing the mergediff of a clean merge will not.

Q: Isn't this the same as git's combined diff?
A: No. Among other things, git's combined diff doesn't show new changes (ie, changes that weren't conflict resolutions) and it only shows resolutions to one of the merge parents. For more examples, compare the output of hg mergediff -r merge to the output of git diff merge^ in the repository created by mktestrepo.


MergediffExtension (last edited 2013-02-21 17:10:04 by KevinBullock)