views:

542

answers:

5

When performing a merge with Mercurial, it wants to merge conflicting files one at a time which just isn't a productive workflow on large merge sets. Instead, what I would like to do is merge the entire changesets of both heads (like using kdiff3 to diff 2 heads). To me that sounds straightforward but I can't figure out how to achieve it.

So far, the closest I can get is to go through the merge the usual way, leave all the conflicts unresolved (a file at a time...), and then hg vdiff -rHead1 -rHead2 - but vdiff (using kdiff3) doesn't seem to have options for passing the tool an output dir (the current working dir) and instead launches with the output dir as a tempdir (possibly -o is the answer?).

Let me put it another way - I want to use kdiff to merge two heads into my working directory. I want the results in my working dir to be my merge that I can commit.

I must be missing something obvious, I can't be the only one who wants to do this.

A: 

Try setting ui.merge. See this page for more details.

Nathan Kitchen
maybe my question isn't clear enough - regardless of the ui.merge setting, I'll still get a file-at-a-time merge from mercurial, rather than an entire changeset vs. changeset merge (unless I'm missing something?)
jsaylor
I'm still a little confused--wouldn't you still need kdiff to show you conflicting files one at a time? Or can it resolve all your conflicts without manual intervention?
Nathan Kitchen
A: 

I think this answers your question.

Jim Hunziker
Good article, but I'm still only looking to merge heads (not changesets in mid branch). My question wasn't entirely clear on this point.
jsaylor
+1  A: 

I relayed the question to #mercurial on irc.freenode.net a couple of days ago. mpm (the author of Mercurial) gave sort of an answer (it was only half an answer, so I didn't immediately pass it on here). He said that one might be able to do something where you let Mercurial merge the files automatically (and insert the <<<< and >>>> merge markers where there are conflicts).

Then use a merge tool that knows about these markers: this will let you resolve them all at once instead of doing it on a file by file basis. A starting point would be the page on merge tool configuration. It explains that

[ui]
merge = internal:merge

will make Mercurial inserte the merge markers. Here I tested it by making two files x.txt and y.txt which I then modified with conflicting changes in two clones. The merge simply gave:

% hg merge
merging x.txt
warning: conflicts during merge.
merging x.txt failed!
merging y.txt
warning: conflicts during merge.
merging y.txt failed!
0 files updated, 0 files merged, 0 files removed, 2 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon

All files were processed in one go, I did not have to confirm anything per file like you describe.

The files now contain merge markers like this:

% cat x.txt
foo
<<<<<<< local
hehe
=======
foobar
>>>>>>> other

The next step is to find a tool that can take a directory tree with such files and let you resolve them. I looked at kdiff3, but did not figure out how to use it to operate on a single file alone, it seems very focused on comparing pairs of files/directories.

I'm not sure how much this half answer helps you -- maybe you also got stuck at this point? But I hope it can help others who want to have the merge markers inserted into all files and then resolve the conflicts by hand.

Martin Geisler
You were close on the notion of letting the unresolved files stick around. I think I came up with a more complete answer, but using this strategy, that I just posted here.
jsaylor
I'm very glad you at least found a way to achieve it, even though it isn't a perfect way. One could make an extension to make the work flow better, but I do so few merges myself that I won't be writing it :-)
Martin Geisler
A: 

sounds like you want the extdiff command:

i have these in my ~/.hgrc (I prefer meld, but you can change it to kdiff3, etc)

[extensions]
hgext.extdiff =

[extdiff]
# add new command called meld, runs meld (no need to name twice)
cmd.meld =

With extdiff your merges occur in your working directory, and moreover you can pass any extra parameters to your diff program with -o:

$ hg help extdiff

hg extdiff [OPT]... [FILE]...

use external program to diff repository (or selected files)

Show differences between revisions for the specified files, using
an external program.  The default program used is diff, with
default options "-Npru".

To select a different program, use the -p option.  The program
will be passed the names of two directories to compare.  To pass
additional options to the program, use the -o option.  These will
be passed before the names of the directories to compare.

When two revision arguments are given, then changes are
shown between those revisions. If only one revision is
specified then that revision is compared to the working
directory, and, when no revisions are specified, the
working directory files are compared to its parent.

options:

-p --program comparison program to run
-o --option pass option to comparison program
-r --rev revision
-I --include include names matching the given patterns
-X --exclude exclude names matching the given patterns

Paul Ivanov
My problem is that is still file by file, and doesn't give me an entire changeset vs. changeset merge approach.
jsaylor
+1  A: 

I came up with a solution that achieves what I want but I still feel like it's a kludge.

  • Start with an empty working dir with 2 heads: Mine and Theirs.
  • Update working dir to Mine:
    hg update [My head's rev here]
  • Perform a merge, but fail all files that Merc can't handle automatically without launching a merge tool and keep "My" files when in conflict:
    hg --config "ui.merge=internal:fail" merge

See http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks#head-9f405488b6d3b3d092a09aafa28db515ba44c742 for how-to merge/fail details.

Now I've got a working dir with as much as auto could figure out, but any outstanding files still untouched from Mine. (Use hg resolve -l to see the Mercurial's resolution status of current files)

  • Now I can vdiff my working dir against the Theirs head which gives me the high level, changeset-to-changeset merge that I was looking for.

hg vdiff -r [Theirs head's rev here]

Note: If you're using WinMerge for your vdiffs , then make sure it has an /r switch as an option which will do a subdirectory compare and - if WinMerge config is set to use Tree-View - will give a great tree comparison. From Mercurial.ini:

[extdiff]
cmd.vdiff = C:\Program Files\WinMerge\WinMergeU.exe
opts.vdiff = /e /ub /r /dl other /dr local

Now I can work the entire directory which includes the unresolved files and make project wide changes as necessary (ie. maybe resolving one file requires additional changes in another).

  • When done use resolve to mark all files resolved for Merc and then commit.
    hg resolve -m

Whew! Here's hoping this helps someone else!

jsaylor