Handling Binary Files in a Merge
posted by Ryan Wilcox on November 30, 2009
Say you’re building a website and you keep your images in the Mercurial repository for the site. Eventually two people are going to change that file at the same time and have a merge conflict.
Setting up Mercurial for Different Merge Tools
In your ~/.hgrc file, you should add the following section:
[merge-tools]
diff_images.args = $output $other
[merge-patterns]
**.png = diff_images
Now, create a diff_images shell script, set it to executable, and put it on
your $PATH. Mine is:
open -a GraphicConverter $1 $2 -W
# opens the first and second parameter with GraphicConverter, waiting
# until same is quit before letting the shell continue.
Now a merge that contains .png files that conflict will open up
GraphicConverter. There will be two images that open up: one as it exists in
the your source tree now, and one from Mercurial. You can tell the difference
because the one from Mercurial will have a lot of random-seeming letters after
the file extension. For example, if your conflicting file is image.png,
GraphicConverter will open up two windows: image.png and
image.png~other.bQkQxd.
Manually move your changes from the new file into the original file
(image.png), saving the original when done and quitting GraphicConverter.
These are the changes that will be committed.
How this Setup Works
First, diff_images.args sets up two parameters to pass into the graphics tool:
$outputis the file that Mercurial will commit, and contains the version from the first parent.$otheris the version from revision you are merging in.
There are other options that the .args parameter provides:
$localis a copy of$output, but changes to this file will be ignored in the merge.$baseis the file from the revision right before the contents of the file diverged.
You could use these to set up a three way merge, if you desired, or enhance
diff_images to show the user the contents of the file before this merge
mess happened.
Next, the [merge-patterns] section associates what merge tool to use when a
file name matches a particular pattern.
Without the merge-pattern section, diff_images would be considered for a
diff candidate, but skipped over because Mercurial will assume that
diff_images can’t handle diffing binary files. Adding lines to
[merge-pattern] will tell Mercurial that diff_images can handle the file
types specified.
Instead of putting in a merge-patterns section, you could add a line, like
diff_images.args, that tells Mercurial that diff_images can handle binary
documents: diff_images.binary = True
However, this will make diff_images a candidate for all binary differences,
which GraphicConverter may not be up to (for example, diffing mp3s would not
be a good task for GraphicConverter).
When Things Go Terribly Wrong: Aborting the Merge
Merges can not be aborted via the standard hg revert mechanism. Try it and
you’ll get:
$ hg revert --all
abort: uncommitted merge - please provide a specific revision
But you just want to blow away your merge work and start from scratch. Use hg
update --clean for this.
References
- Merge Tool Configuration on the Mercurial Wiki
- Issue 1533: “abort: outstanding uncommitted merges should mention update -C”
- Binary Files in Mercurial explained, on the Mercurial Wiki