外部差分ツールの利用

--diff-cmd--diff3-cmd オプションや 同じような名前の実行時環境パラメータ(config項参照)がある ので、Subversion で外部差分ツール(あるいは 「diff」)とマージツールを 使うのは簡単なことだという間違った考えを持ってしまうかも知れません。 Subversion ではそのようなよく知られたほとんどのツールを使うことが できますが、このような設定に必要な努力はそれほど簡単ではないことが よくあります。

Subversion と外部 diff と merge ツールは Subversion の唯一の文脈差分 を出力する能力が GNU の diffutils の連携した呼び出しだけであった ころに由来しています。具体的には diffdiff3 ユーティリティーです。Subversion が必要とする ような動作をさせるには、そのようなユーティリティーをかなりたくさんの オプションと引数で呼び出されました。それらのほとんどはそれぞれの ユーティリティーごとの非常に特殊なオプションでした。ある時点から Subversion は自分自身の内部差分ライブラリを持つようになり、エラー回避の仕組みとして の [51] --diff-cmd--diff3-cmd オプションが Subversion コマンドラインクライアントに追加されていて、 これによってユーザは、新しい内部 diff ライブラリを使うかわりに自分の 好きな GNU diff や diff3 ユーティリティーを使うこともできたのです。 このようなオプションが利用された場合、Subversion は単に内部 diff ライブラリを無視し、そのような外部プログラムを長い引数つきで実行します。 これが、このようなオプションが今でも残っている理由です。

Subversion がシステム中の特定のディレクトリにある外部 GNU diff と diff3 ユーティリティーを利用するための簡単な設定の仕組みは他の diff や merge ツールにも一般的に利用できることに開発チームが気づくまでにはそんなに 長い時間はかかりませんでした。要するに Subversion は実際に実行せよと 言われた外部ツールが GNU diffutils のツールの組み合わせであるかどうか を実際には確認していなかったのです。しかしこれらの外部ツールを利用する ための、そのツールのシステム中の場所だけは設定しなくてはなりません— 必要なオプションと、パラメータの順序、などを指定するのはもちろんのこと ですが。Subversion は、このような GNU ユーティリティー用のオプションの すべてを、実際にそのオプションが理解されるかどうかにかかわりなく 外部 diff ツールに渡します。そしてここがほとんどのユーザにとって 直観的には理解しにくい部分です。

外部 diff と merge ツール(もちろん GNU diff と diff3 以外のものも含みますが) を Subversion で利用するときの鍵は、Subversion からの入力をその差分ツールが 理解できる何らかの形に変換し、そのツールからの出力内容— それは たとえば GNU ツールが利用しているような書式ということになるのでしょうが— を Subversion 側で理解できる形に変換するようなラッパースクリプトを使うことです。 以下の節ではこのような考え方を具体的に述べます。

注意

Subversion の処理の一部として文脈 diff や merge をいつ利用するかの判断は 完全に Subversion 側で決定され、操作対象となるファイルが人間によって 可読な形式であるかどうかは他の場合と同様 svn:mime-type 属性によって決められます。これによって、例えば、仮にあなたが宇宙で一番 すぐれた Microsoft Word 用の差分とマージツールを手にしていたとしても、 そのバージョン化された Word ドキュメントが人間によって可読ではないことを 示す MIME タイプに設定されていなければ(たとえば application/mswordのようなもの)決して起動されることは ないでしょう。MIME タイプの設定についての詳細は ファイルの内容タイプ項を見て ください。 ファイルの内容タイプ項

外部 diff

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 programs, 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 error code of 1 if your program detected differences, or 0 if it did not—any other error code is considered a fatal error. [52]

例 7.2. 「diffwrap.sh」例 7.3. 「diffwrap.bat」 はそれぞれ Bourne シェルと Windows バッチスクリプト言語での外部 diff ツールの ラッパー用テンプレートです。

例 7.2. diffwrap.sh

#!/bin/sh

# ここに自分の好きな diff プログラムを設定してください。
DIFF="/usr/local/bin/my-diff-tool"

# Subversion は 6 番目と 7 番目の引数としてパス名が必要です
LEFT=${6}
RIGHT=${7}

# diff コマンドを呼び出します (merge プログラムで意味を持つように
# 以下の行を変更してください。)
$DIFF --left $LEFT --right $RIGHT

# 差分がなけばエラーコード 0 を、差分があれば 1 を返します。
# それ以外のエラーコードは致命的とみなします。

例 7.3. diffwrap.bat

@ECHO OFF

REM ここに自分の好きな diff プログラムを設定してください。
SET DIFF="C:¥Program Files¥Funky Stuff¥My Diff Tool.exe"

REM Subversion は 6 番目と 7 番目の引数としてパス名が必要です
SET LEFT=%6
SET RIGHT=%7

REM diff コマンドを呼び出します (merge プログラムで意味を持つように
REM 以下の行を変更してください。)
%DIFF% --left %LEFT% --right %RIGHT%

REM 差分がなけばエラーコード 0 を、差分があれば 1 を返します。
REM それ以外のエラーコードは致命的とみなします。

外部 diff3

Subversion calls external merge programs with parameters suitable for the GNU diff3 utility, expecting that the external program return with a successful error code and that the full file contents which result from the completed merge operation are printed on the standard output stream (so that Subversion can redirect them into the appropriate version controlled file). For most alternative merge programs, only the ninth, tenth, and eleventh arguments, the paths of the files which represent the 「mine」, 「older」, and 「yours」 inputs, respectively, are of interest. Note that because Subversion depends on the output of your merge program, you wrapper script must not exit before that output has been delivered to Subversion. When it finally does exit, it should return an error code of 0 if the merge was successful, or 1 if unresolved conflicts remain in the output—any other error code is considered a fatal error.

例 7.4. 「diff3wrap.sh」例 7.5. 「diff3wrap.bat」 はそれぞれ Bourne シェルと Windows バッチスクリプト言語用の外部マージツール ラッパーのテンプレートです。

例 7.4. diff3wrap.sh

#!/bin/sh

# ここに自分の好きな diff3/merge プログラムを設定してください。
DIFF3="/usr/local/bin/my-merge-tool"

# Subversion は必要となるパスを、9, 10, 11 番目の引数として用意します。
MINE=${9}
OLDER=${10}
YOURS=${11}

# merge コマンドを呼び出します (merge プログラムで意味を持つように
# 以下の行を変更してください。)
$DIFF3 --older $OLDER --mine $MINE --yours $YOURS

# マージ処理実行後、このスクリプトはマージされたファイル内容を標準出力に
# 表示す必要があります。適切だと考える方法でこれを行ってください。
# エラーコード 0 はマージ成功を、1 は解消不能な競合が結果に残ったことを
# 示します。それ以外のエラーコードは致命的とみなします。

例 7.5. diff3wrap.bat

@ECHO OFF

REM ここに自分の好きな diff3/merge プログラムを設定してください。
SET DIFF3="C:¥Program Files¥Funky Stuff¥My Merge Tool.exe"

REM Subversion は必要となるパスを、9, 10, 11 番目の引数として用意しますが、
REM 一度にアクセスできる引数の数は 9 個までなので、必要な引数を取得するため
REM 取得前に 9 個のパラメータウィンドウを二回シフトしておきます。
SHIFT
SHIFT
SET MINE=%7
SET OLDER=%8
SET YOURS=%9

REM merge コマンドを呼び出します (merge プログラムで意味を持つように
REM 以下の行を変更してください。)
%DIFF3% --older %OLDER% --mine %MINE% --yours %YOURS%

REM マージ処理実行後、このスクリプトはマージされたファイル内容を標準出力に
REM 表示す必要があります。適切だと考える方法でこれを行ってください。
REM エラーコード 0 はマージ成功を、1 は解消不能な競合が結果に残ったことを
REM 示します。それ以外のエラーコードは致命的とみなします。



[51] Subversion 開発者はもちろんみんな優秀ですが、猿も木から落ちるといいます。

[52] GNU diff のマニュアルには以下のようにあります: 「 0 の終了コードは差分がなかったことを意味し、1 は何か差分があったことを、また 2 は処理に異常があったことを示します。