Why is mercurial dumb when merging? How can I make pulling/merging changes simpler?

798 Views Asked by At

I just started to use Mercurial and I think I'm trying to do something very simple, something that should be quite typical, but I'm stumped on why it's so complicated, and why it doesn't just work the way it should (IMO).

I share some a repository with a friend, he makes some changes and checks in several files and pushes them. Now in svn I'm used to just updating my working copy and getting his changes, no hassle. But with mercurial apparently I have to merge. What I don't get is: shouldn't mercurial be smart enough to figure out that if my friend made the most recent changes, and I haven't touched the files, that it should just use his version of the file?? Apparently it can't figure that out, and instead it tries to merge the files which utterly fails (actually I have installed Beyond Compare which automatically opened, so I can't blame mercurial entirely for the bad merge).

At any rate, I don't know why it even has to "merge" the files when it's obvious (to me) that it should just have taken the remote (i.e. most recent) changes. Am I doing anything wrong in how I'm using the tool, or is there anything I can do to make it work in a simpler way (the way I'm used to it just working in subversion)... is there any configuration settings, any tips on command line flags I can use to have it work better?

1

There are 1 best solutions below

2
On

You only need to merge if you've committed in your repository as well. If you share the repository with your friend, he commits one or more times while you're not doing anything, when he's done all you have to do is pull and update, no merging.

If you've done local commits, here's how the scenario unfolds:

local:    1---2---3---4
central:  1---2---3---4
friend:   1---2---3---4

He commits:

local:    1---2---3---4
central:  1---2---3---4
friend:   1---2---3---4---5---6

You commit:

local:    1---2---3---4---X---Y
central:  1---2---3---4
friend:   1---2---3---4---5---6

He pushes:

local:    1---2---3---4---X---Y
central:  1---2---3---4---5---6
friend:   1---2---3---4---5---6

You pull:

local:    1---2---3---4---X---Y
                       \
                        +-5---6

central:  1---2---3---4---5---6
friend:   1---2---3---4---5---6

You merge:

local:    1---2---3---4---X---Y---7
                       \         /
                        +-5---6-+

central:  1---2---3---4---5---6
friend:   1---2---3---4---5---6

Then you push and he pulls, and all the repositories are identical.

However, if you haven't done anything while he has worked on the project, here's how that scenario unfolds:

local:    1---2---3---4
central:  1---2---3---4
friend:   1---2---3---4

He commits:

local:    1---2---3---4
central:  1---2---3---4
friend:   1---2---3---4---5---6

He pushes:

local:    1---2---3---4
central:  1---2---3---4---5---6
friend:   1---2---3---4---5---6

You pull and update:

local:    1---2---3---4---5---6
central:  1---2---3---4---5---6
friend:   1---2---3---4---5---6

The reason this is different from how Subversion did it is that with Subversion you had the centralized repository that everybody had to talk to.

As such, when you got around to committing your local changes, the Subversion client would say "sorry, you need to update before you can commit", and you had to execute that update.

If, at that point, you have changed files that are also changed in the central repository, Subversion would merge your local changes with the server changes and update your revision point up to the tip. If there were no conflicts, this would be a silent merge, otherwise you would get merge conflicts.

Mercurial does the exact same thing, except that the merge is not silent. You can both commit individually, in your own local repositories, without ever talking to each other, but when you try to integrate all the changes into one common repository, you need to merge. Mercurial never changes existing changesets (unless you use some extensions for history editing) so it cannot just automatically figure out how your parallell changesets would work together.

If you two haven't worked on the same files, or the changes you've done to the same files are not in conflict with each other, then the merge is just a few clicks away and you're done.

In any case, Mercurial got many options, but the distributed part really changes how you need to think about your history.