外部差分ツールの利用

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

Subversion と外部 diff と merge ツールは Subversion の唯一の文脈差分 を出力する能力が GNU の diffutils の連携した呼び出しだけであった ころに由来しています。具体的には diffdiff3 ユーティリティーです。Subversion が必要とする ような動作をさせるには、そのようなユーティリティーをかなりたくさんの オプションと引数で呼び出されました。それらのほとんどはそれぞれの ユーティリティーごとの非常に特殊なオプションでした。ある時点から Subversion は自分自身の内部差分ライブラリを持つようになり、エラー回避の仕組みとして の [39] --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 タイプの設定についての詳細は svn:mime-typeを見て ください。

外部 diff

Subversion は外部 diff プログラムを GNU diff ユーティリティーにふさわしい 引数で呼び出し、その外部プログラムには単に成功したことを示すエラーコード を返すことだけを期待します。その他のほとんどの diff プログラムでは 六番目と七番目の引数、これは diff の左側と右側にそれぞれ対応したファイルの パスになりますが、それだけが関係してきます。Subversion は Subversion の操作によって修正されたファイルごとに diff プログラムを起動する ため、その外部プログラムが非同期的に実行される(あるいは「バックグラウンド」 で実行される)場合にはすべてのインスタンスが同時に実行されてしまうかも知れない ことに注意してください。最後に Subversion はそのプログラムが差分を検出した場合 0 を、また検出しなかった場合には 1 をエラーコードとして返すものとして扱います —これ以外のエラーは致命的なエラーとみなします。 [40]

例 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 は外部マージプログラムを GNU diff3 ユーティリティーにふさわしい 引数で呼び出し、この外部プログラムが成功を示すエラーコードで戻り、 完了したマージ処理の結果としてのファイル内容の全体が標準出力ストリームに 出力されることを期待します(これによって Subversion はその内容を 適切なバージョン管理下にあるファイルにリダイレクトすることができます)> その他のほとんどのマージプログラムでは 9 番目、10番目、そして 11 番目の 引数だけが処理に関係してきます。これらはそれぞれ 「自分側のファイル(mine)」、 「マージ元になる古いファイル(older)」、そして 「相手側のファイル(yours)」の内容になります。 Subversion はそのマージプログラムの出力に依存するので、ラッパースクリプトは 出力が Subversion に転送されてしまうまで終了してはいけません。最終的に プログラムが終了した際にマージが成功していれば 0 を、解消できない衝突が 出力中に残っている場合には 1 を返します — それ以外のエラーコードは 致命的なものとみなします。

例 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 示します。それ以外のエラーコードは致命的とみなします。



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

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