views:

155

answers:

1

I'm trying to get in the habit of doing code reviews, but merges have been making the process difficult because I don't know how to ask Mercurial to "show only changes introduced by the merge which were not present in either of its parents."

Or, slightly more formally (thanks to Steve Losh):

Show me every hunk in the merge that wasn't present in either of its parents, and show me every hunk present in either of its parents that isn't also present in 3.

For example, assume I have a repository with two files, a and b. If "a" is changed in revision 1, "b" is changed in revision 2 (which is on a separate branch) and these two changes are merged in revision 3, I'll get a history which looks like this:

    @    changeset:   3
    |\   summary:     Merged.
    | |
    | o  changeset:   2
    | |  summary:     Changing b
    | |
    o |  changeset:   1
    |/   summary:     Changing a
    |
    o  changeset:   0
       summary:     Adding a and b

But if I ask to see the changes introduced by revision 3, hg di -c 3, Mercurial will show me the same thing as if I asked to see the changes introduced in revision 1, hg di -c 1:

    $ hg di -c 3
    --- a/a     
    +++ b/a     
    @@ -1,1 +1,1 @@ 
    -a 
    +Change to a
    $ hg di -c 1
    --- a/a     
    +++ b/a     
    @@ -1,1 +1,1 @@ 
    -a 
    +Change to a

But, obviously, this isn't very helpful - instead, I would like to be told that no new changes were introduced by revision 3 (or, if there was a conflict during the merge, I would like to see only the resolution to that conflict). Something like:

    $ hg di -c 3
    $

So, how can I do this?

ps: I know that I can reduce the number of merges in my repository using rebase… But that's not my problem - my problem is figuring out what was changed with a merge.

+3  A: 

The short answer: you can't do this with any stock Mercurial command.

Running hg diff -c 3 will show you the changes between 3 and its first parent -- i.e. the changeset you were at when you ran hg merge.

This makes sense when you think of branches as more than just simple changesets. When you run hg up 1 && hg merge 2 you're telling Mercurial: "Merge changeset 2 into changeset 1".

It's more obvious if you're using named branches. Say changeset 2 in your example was on a named branch called rewrite-ui. When you run hg update 1 && hg merge rewrite-ui you're effectively saying: "Merge all the changes in the rewrite-ui branch into the current branch." When you later run hg diff -c on this changeset it's showing you everything that was introduced to the default branch (or whatever branch 1 happens to be on) by the merge, which makes sense.

From your question, though, it looks like you're looking for a way to say:

Show me every hunk in this changeset that wasn't present in either of its parents, and show me every hunk present in either of its parents that isn't also present in 3.

This isn't a simple thing to calculate (I'm not even sure I got the description right just now). I can definitely see how it would be useful, though, so if you can define it unambiguously you might convince one of us Mercurial contributors that read SO to implement it.

Steve Losh
Hrm, it looks like I forgot to say the obvious earlier: thanks for the answer.Anyway, have you heard from any HG devs who might be interested in banging something up? Or, alternatively, would you (or someone else?) mind if I bugged them while I try to figure out how to implement this?
David Wolever
I'd be interested because it would be really nice to have a sane "merge diff" for the hg-review extension I'm working on. I'm sjl in #mercurial on freenode -- hit me up.
Steve Losh