Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mercurial and merge tools?

Is Mercurial always using the external merge tools when two branches that are merging have changes to the same file?

Or does it first see if it can merge the file itself, and only punting to the external tool if it can't?

The reason I'm asking is that I am (once again) re-reading the tutorial written by Joel Spolsky on Mercurial and one thing he says, when comparing how Subversion and Mercurial is merging is that:

By contrast, while we were working separately in Mercurial, Mercurial was busy keeping a series of changesets. And so, when we want to merge our code together, Mercurial actually has a whole lot more information: it knows what each of us changed and can reapply those changes, rather than just looking at the final product and trying to guess how to put it together.

Only, my experience tells me that it seems to involve the external merge tool when two branches have changes to the same files. And thus, doesn't that render the above argument incorrect?

Or should I interpret this as follows:

  • Subversion only merges the final state of the two branches, and has more work to do in a single unit
  • Mercurial merges each changeset individually, which allows it to work with smaller units of changes, with higher chance of merge success

Can someone shed some light on this?


Edit: Let me give an example:

@echo off

setlocal

if exist repo rd /s /q repo

md repo
cd repo
hg init .

rem --- version 0 ---
echo 1 >test.txt
echo 2 >>test.txt
echo 3 >>test.txt
echo 4 >>test.txt
echo 5 >>test.txt
hg add test.txt
hg commit -m "v0"

rem --- version 1 ---
echo 1 >test.txt
echo 2 v1 >>test.txt
echo 3 >>test.txt
echo 4 >>test.txt
echo 5 >>test.txt
hg commit -m "v1"

rem --- version 2 ---
hg update 0
echo 1 >test.txt
echo 2 >>test.txt
echo 3 >>test.txt
echo 4 v2 >>test.txt
echo 5 >>test.txt
hg commit -m "v2"

rem --- merge ---
hg update 1
hg merge 2

This first creates a file with the following content:

1
2
3
4
5

Then it changes it to:

1
2 v1
3
4
5

Then it goes back to the initial version (changeset), and changes it to:

1
2
3
4 v2
5

Then it attempts to merge the two.

Now, according to the (currently) single answer, this should not pose a problem, since the changes are not in conflict.

However, at this point, Beyond Compare (my external merge tool) is invoked.

like image 537
Lasse V. Karlsen Avatar asked Jul 09 '10 19:07

Lasse V. Karlsen


People also ask

What are merge tools?

What Is the Merge Tool? The Merge Tool combines data from multiple sources, then adds them into a new data set. It's not only geometry, but it also merges attributes with the option to match fields from input datasets. When you use the Merge Tool, features have to be the same geometry type (points, lines, or polygons).

How does mercurial resolve merge conflict?

To resolve the conflict, we open 'hello. c' in an editor, delete the conflict markers and keep the "sure am glad I'm using Mercurial!\ n" line, deleting the line about CVS. We can then save and quit the editor.

How do I merge Mercurials?

To merge two branches, you pull their heads into the same repository, update to one of them and merge the other, and then commit the result once you're happy with the merge. The resulting changeset has two parents.

How do you merge Heads in Mercurial?

To start a merge between the two heads, we use the hg merge command. We resolve the contents of hello. c This updates the working directory so that it contains changes from both heads, which is reflected in both the output of hg parents and the contents of hello.


2 Answers

The big difference between mercurial merging and svn merging is that the mercurial merge algorithm has access to the last-common-ancestor between the two revisions being merged. If your history looks like

A--B
 \-C

svn will turn your merge tools lose on B and C. Mercurial will launch your tool with A, B, and C and some tools do better stuff with that.

Mercurial does do its own internal merge before launching your tool where it uses A, B, and C to make some of the obvious choices itself. You can turn that off by altering the premerge setting for a tool.

Your test isn't giving great results because you're merging 2 with its own ancestor. If instead you do a hg update 0 before creating changeset 2, so you have an actual branching history like this:

@  changeset:   2:790856e061f4
|  tag:         tip
|  parent:      0:bfba1d8f77af
|  user:        Ry4an Brase
|  date:        Fri Jul 09 16:50:34 2010 -0500
|  summary:     added v2
|
| @  changeset:   1:7a9c581561b6
|/   user:        Ry4an Brase
|    date:        Fri Jul 09 16:50:16 2010 -0500
|    summary:     added v1
|
o  changeset:   0:bfba1d8f77af
   user:        Ry4an Brase
   date:        Fri Jul 09 16:49:29 2010 -0500
   summary:     first

then when you hg merge you'll get:

1
2 v1
3
4 v2
5

without your merge tool launching.

like image 181
Ry4an Brase Avatar answered Sep 27 '22 18:09

Ry4an Brase


The mergetool is invoked only in case there's a conflict that needs to be resolved. Changes to the same file in different branches constitutes such a conflict.

Other than that, the actual merge algorithm isn't changeset based, it's file based to allow for best merge results. See the Mercurial Wiki for more details.

Mercurial leaves your merge uncomitted, so you have a chance to check your code before comitting the merge changeset.

like image 23
Johannes Rudolph Avatar answered Sep 27 '22 18:09

Johannes Rudolph