DiffMerge

SourceGear DiffMerge

DiffMerge is an free 3-way merge tool by SourceGear that runs on Windows, Mac, and Linux.

With the 3.3.0 release (April 2009), DiffMerge is compatible with Mercurial external merge feature. When the --result=file argument is used, DiffMerge writes the merge result to the given file and exits with 0 (merge resolved), 1 (merge aborted), or 2 (other error). Note that DiffMerge does not handle binary files so you'll want to configure another tool for them.

You can also use DiffMerge as an external diff viewer using the extdiff extension feature. With the changes below, you can type hg diffmerge instead of hg diff.

To enable both diffing and merging with DiffMerge, add the following to your .hgrc or Mercurial.ini file:

[ui]
merge = diffmerge

[extensions]
hgext.extdiff =

[extdiff]
cmd.diffmerge = /usr/bin/diffmerge

[merge-tools]
diffmerge.executable = /usr/bin/diffmerge
diffmerge.args = -merge -result=$output -t1="Local Version" -t2=$output -t3="Other Version" -caption=$output $local $base $other
diffmerge.binary = False
diffmerge.symlinks = False
diffmerge.gui = True

On Windows, the executable should be: c:\Program Files\SourceGear\DiffMerge\DiffMerge.exe.

On Mac OS X, please also install the command-line shell script that was included on the DMG; see the README for details.

Prior to the 3.3.0 release, DiffMerge was not directly compatible with Mercurial. It always returns 0 as its exit code, which causes Mercurial to assume that the merge was successful. It also merges to one of the Mercurial temporary files instead of the local file. The python script below fixes both of these problems. It runs on Python 2.5 and later. (On Mac and Linux, you will need to update the paths in the locations list to point to where you have DiffMerge installed.) Since DiffMerge does not handle binary files you will want to add the following to your hgrc file:

hgrc files changes

[ui]
merge = diffmerge

[merge-tools]
diffmerge.binary = False

diffmerge.py

locations = ['C:\\Program Files\\SourceGear\\DiffMerge\\diffmerge.exe',
             'C:\\Program Files (x86)\\SourceGear\\DiffMerge\\diffmerge.exe',
             '/Applications/DiffMerge.app/Contents/MacOS/DiffMerge',
             '/usr/bin/diffmerge']

import hashlib
import sys
import subprocess
import os
import shutil

def hashFile(filename):
  m = hashlib.md5()
  with open(filename) as f:
    m.update(f.read() + str(os.path.getmtime(filename)))
  return m.digest()

local = sys.argv[1]
base = sys.argv[2]
other = sys.argv[3]

validLocations = filter(os.path.exists, locations)
if len(validLocations) == 0:
  print("DiffMerge not found")
  sys.exit(1)
diffmerge = validLocations[0]

oldhash = hashFile(base)
# Works on Windows according to (IRC nick) Zephtar (orignial author)
#cmd = '"%s" "%s" "%s" "%s"' % (diffmerge, local, base, other)
# Works on OS X and Correct according to doc:
# http://docs.python.org/library/subprocess.html#subprocess.Popen
cmd = (diffmerge, local, base, other)
p = subprocess.Popen(cmd)
p.wait()
newhash = hashFile(base)

if oldhash == newhash:
  sys.exit(1)
else:
  shutil.copyfile(base, local)
  sys.exit(0)

DiffMerge (last edited 2012-11-11 12:54:18 by abuehl)