Using External Differencing Tools
The presence of --diff-cmd
and
--diff3-cmd
options, and similarly named
runtime configuration parameters (see
the section called “Config”), can lead to a
false notion of how easy it is to use external differencing (or
“diff”) and merge tools with Subversion. While
Subversion can use most of popular such tools available, the
effort invested in setting this up often turns out to be
non-trivial.
The interface between Subversion and external diff and merge
tools harkens back to a time when Subversion's only contextual
differencing capabilities were built around invocations of the
GNU diffutils toolchain, specifically the
diff
and
diff3
utilities.
To get the kind of behavior Subversion needed, it called these
utilities with more than a handful of options and parameters,
most of which were quite specific to the utilities. Some time
later, Subversion grew its own internal differencing library,
and as a failover mechanism,
[40]
the --diff-cmd
and --diff3-cmd
options were added to the Subversion command-line client so
users could more easily indicate that they preferred to use the
GNU diff and diff3 utilities instead of the newfangled internal
diff library. If those options were used, Subversion would
simply ignore the internal diff library, and fall back to
running those external programs, lengthy argument lists and all.
And that's where things remain today.
It didn't take long for folks to realize that having such
easy configuration mechanisms for specifying that Subversion
should use the external GNU diff and diff3 utilities located at
a particular place on the system could be applied toward the use
of other diff and merge tools, too. After all, Subversion
didn't actually verify that the things it was being told to run
were members of the GNU diffutils toolchain. But the only
configurable aspect of using those external tools is their
location on the system—not the option set, parameter
order, etc. Subversion continues throwing all those GNU utility
options at your external diff tool regardless of whether or not
that program can understand those options. And that's where
things get unintuitive for most users.
The key to using external diff and merge tools (other than
GNU diff and diff3, of course) with Subversion is to use wrapper
scripts which convert the input from Subversion into something
that your differencing tool can understand, and then to convert
the output of your tool back into a format which Subversion
expects—the format that the GNU tools would have used.
The following sections cover the specifics of those
expectations.
Note
The decision on when to fire off a contextual diff or
merge as part of a larger Subversion operation is made
entirely by Subversion, and is affected by, among other
things, whether or not the files being operated on are
human-readable as determined by their
svn:mime-type
property. This means, for
example, that even if you had the niftiest Microsoft
Word-aware differencing or merging tool in the Universe, it
would never be invoked by Subversion so long as your versioned
Word documents had a configured MIME type that denoted that
they were not human-readable (such as
application/msword
). For more about MIME
type settings, see
the section called “svn:mime-type
”
Subversion calls external diff programs with parameters
suitable for the GNU diff utility, and expects only that the
external program return with a successful error code. For
most alternative diff program, only the sixth and seventh
arguments, the paths of the files which represent the left and
right sides of the diff, respectively, are of interest. Note
that Subversion runs the diff program once per modified file
covered by the Subversion operation, so if your program runs
in an asynchronous fashion (or “backgrounded”),
you might have several instances of it all running
simultaneously. Finally, Subversion expects that your program
return an errorcode of 0 if your program detected differences,
or 1 if it did not—any other errorcode is considered a
fatal error.
[41]
Example 7.2, “diffwrap.sh”
and
Example 7.3, “diffwrap.bat”
are templates for external diff tool wrappers in the Bourne
shell and Windows batch scripting languages,
respectively.
Example 7.2. diffwrap.sh
#!/bin/sh
# Configure your favorite diff program here.
DIFF="/usr/local/bin/my-diff-tool"
# Subversion provides the paths we need as the sixth and seventh
# parameters.
LEFT=${6}
RIGHT=${7}
# Call the diff command (change the following line to make sense for
# your merge program).
$DIFF --left $LEFT --right $RIGHT
# Return an errorcode of 0 if no differences were detected, 1 if some were.
# Any other errorcode will be treated as fatal.
Example 7.3. diffwrap.bat
@ECHO OFF
REM Configure your favorite diff program here.
SET DIFF="C:\Program Files\Funky Stuff\My Diff Tool.exe"
REM Subversion provides the paths we need as the sixth and seventh
REM parameters.
SET LEFT=%6
SET RIGHT=%7
REM Call the diff command (change the following line to make sense for
REM your merge program).
%DIFF% --left %LEFT% --right %RIGHT%
REM Return an errorcode of 0 if no differences were detected, 1 if some were.
REM Any other errorcode will be treated as fatal.
[an error occurred while processing this directive]