Friday, April 29, 2011

Incremental Merge with Mercurial

I just learned how to merge incrementally with Mercurial. I wasn't really even aware of what that means until I learned about it. Most people use a graphical diff/merge tool with Mercurial such as kdiff3, and for a good reason. Resolving merge conflicts any other way is much more difficult. Normally when you run hg merge it merges all the files right then, and pops up your graphical merge tool right when conflicts occur. You can leave the gui window up and sort of ignore it for a while, but then you wonder what happens if your computer loses power or you need to reboot for some reason. Will your working copy be left in some weird state? What if you have already spent a lot of time resolving tricky conflicts on a previous file, you'd hate to lose that work. Or what if you know one particular file is going to be onerous and you'd like to resolve conflicts there first? Wouldn't it be nice if Mercurial could just present you a list of files with conflicts and let you deal with them on your own time and in the order that you choose? It turns out, Mercurial can do just that. Here's how:

hg merge --tool internal:merge

The first command tells mercurial to use its (not so smart) non-interactive merge tool. If it comes across a conflict it inserts markers into your files. As an alternative you can specify the internal:dump merge tool. Instead of putting markers into your files, it creates three new files with a .other, .local, and .base extension, which are a little easier to use if you want to do some manual inspection of the various versions. The cool thing, in either case, is you don't have to do anything manual. First things first though. You can now see which files have merge conflicts by typing:

hg resolve --list

Those with a U in front of them have unresolved conflicts and need some attention. Those with R in front are just fine. Here's the best part. To resolve the conflicts for a given file using your favorite diff/merge tool, and I'll use kdiff3 as an example, type this:

hg resolve --tool kdiff3 filename

The file is merged with kdiff3 (or your tool of choice) just like it would have been with a regular hg merge command. In the case of kdiff3, it's smarter than the internal Mercurial merge tool and it may resolve the conflicts without popping up a window and asking for your help. Be happy when that happens.

You can also just manually edit the files to resolve the conflicts. If you do that, type:

hg resolve -m filename

to let Mercurial know you've taken care of it. Once you see all R files when you type hg resolve --list you're all done. You can run your tests and then commit the merge.

This isn't very useful for simple merges, but for big complicated merges (where, maybe, you have waited too long and two branches have diverged a lot), this is a really nice technique.

No comments: