Subversionにおける svn diff
コマンド徹底解説 – 使い方、オプション、応用例を網羅
はじめに:バージョン管理システムと差分(Diff)の重要性
ソフトウェア開発やドキュメント管理において、バージョン管理システムは不可欠なツールです。変更履歴を記録し、複数の開発者間の協調作業を容易にし、問題発生時には過去の安定した状態に戻すことを可能にします。数あるバージョン管理システムの中でも、Subversion(SVN)は集中型バージョン管理システムの代表格として広く利用されてきました。
バージョン管理システムを利用する上で、最も基本的な操作の一つが「差分の確認」です。自分がローカルで行った変更が、サーバー上の最新版と比較してどうなっているのか? 特定の機能が導入される前と後で、コードはどのように変わったのか? 過去のバグ修正で、具体的にどの行が変更されたのか? こうした疑問に答えるのが、差分表示機能です。
Subversionにおける差分表示の中核を担うコマンドが svn diff
です。このコマンドを使いこなすことで、バージョン管理の効率が格段に向上し、意図しない変更の混入を防ぎ、問題発生時の原因究明を助け、チーム内でのコードレビューなどを円滑に進めることができます。
本記事では、svn diff
コマンドの最も基本的な使い方から、様々なオプションを組み合わせた応用的な利用方法、さらに外部ツールとの連携や実行時の注意点に至るまで、詳細かつ網羅的に解説します。約5000語を費やし、この強力なコマンドの全てを明らかにします。
svn diff
コマンドの基本構造と出力形式
svn diff
コマンドは、大きく分けて「作業コピー」と「リポジトリ上のパス/リビジョン」の間、または「リポジトリ上の2つのパス/リビジョン」の間の差分を表示します。最も一般的な使い方は、引数なしで実行する場合です。
bash
svn diff [PATH]
または
bash
svn diff [TARGET1 [TARGET2]]
最も基本的な使い方:作業コピーとHEADリビジョンの比較
引数なしで svn diff
を実行すると、現在の作業コピーの状態と、それがチェックアウトされた時点でのリポジトリの最新版(HEADリビジョン)との間の差分が表示されます。具体的には、作業コピーで変更、追加、削除されたファイルの内容やプロパティの差分が表示されます。
bash
$ svn diff
このコマンドは、コミットする前に自分の変更内容を確認するために頻繁に利用されます。
特定のファイルやディレクトリの差分だけを見たい場合は、引数にパスを指定します。
bash
$ svn diff myfile.c
$ svn diff mydirectory/
ディレクトリを指定した場合、そのディレクトリ内のすべてのファイルとサブディレクトリに対して、再帰的に差分が表示されます。
出力形式:Unified Diff Format
svn diff
のデフォルトの出力形式は、多くのバージョン管理システムや差分ツールで広く採用されている Unified Diff Format です。この形式は、どのファイルが変更されたか、どの行が追加・削除・変更されたかをコンパクトに表現します。
Unified Diff Formatの基本的な構造は以下の通りです。
-
ヘッダー行:
--- a/path/to/file
: 変更前のファイル(通常は作業コピーの元になったリポジトリの状態)+++ b/path/to/file
: 変更後のファイル(通常は作業コピーの現在の状態)---
の行には、変更前のファイルのリビジョン情報などが含まれることもあります。+++
の行には、変更後のファイルの情報が含まれます。
-
チャンクヘッダー行:
@@ -l,s +l,s @@
: 差分のあるブロック(チャンク)の範囲を示します。-l,s
: 変更前のファイルにおいて、差分が始まる行番号l
と、そこからs
行(もしs
が1の場合は省略されることが多い)が対象であることを示します。+l,s
: 変更後のファイルにおいて、差分が始まる行番号l
と、そこからs
行が対象であることを示します。@@
より後ろには、コンテキストを示す情報(関数名など)が表示されることがあります。
-
差分内容:
- 各行の先頭に以下の記号が付きます。
(スペース): 前後のファイルで変更がない行(コンテキストとして表示される)
+
: 変更後のファイルに追加された行-
: 変更前のファイルから削除された行- 通常、変更は「古い行が削除され、新しい行が追加された」として表現されます。例えば、
int x = 0;
をint x = 1;
に変更した場合、- int x = 0;
と+ int x = 1;
のように表示されます。
- 各行の先頭に以下の記号が付きます。
出力例の解説
例えば、main.c
というファイルで以下のような変更を行ったとします。
元のファイル (HEAD
):
“`c
include
int main() {
printf(“Hello, world!\n”);
return 0;
}
“`
変更後のファイル (WORKING
):
“`c
include
include “myheader.h” // 追加
int main() {
// 標準出力にメッセージを出力
printf(“Hello, SVN diff!\n”); // 変更
return 0;
}
“`
この状態で svn diff main.c
を実行すると、以下のような出力が得られるでしょう(実際の出力はSubversionのバージョンや設定により若干異なる場合があります)。
“`diff
— main.c (リビジョン 12345)
+++ main.c (作業コピー)
@@ -1,6 +1,7 @@
#include
+#include “myheader.h” // 追加
int main() {
– printf(“Hello, world!\n”);
+ // 標準出力にメッセージを出力 // 追加
+ printf(“Hello, SVN diff!\n”); // 変更(元の行が削除され、新しい行が追加されたように見える)
return 0;
}
“`
--- main.c ...
は元のファイル (HEAD
, リビジョン12345) を示し、+++ main.c ...
は変更後のファイル (作業コピー
) を示します。@@ -1,6 +1,7 @@
は、差分が元のファイルの1行目から6行、変更後のファイルの1行目から7行に関わることを示しています。+#include "myheader.h" // 追加
の行は、変更後のファイルに追加された行です。- printf("Hello, world!\n");
は、元のファイルから削除された行です。+ // 標準出力にメッセージを出力 // 追加
は、変更後のファイルに追加された行です。+ printf("Hello, SVN diff!\n"); // 変更
は、元の行- printf("Hello, world!\n");
に対応する、変更後の行です。
ファイルの追加・削除の表示
ファイルが作業コピーに追加された場合、そのファイル全体が「追加された内容」として表示されます。
diff
--- /dev/null
+++ b/new_file.txt
@@ -0,0 +1,3 @@
+This is a new file.
+It contains some content.
+Line 3.
--- /dev/null
は、変更前のファイルが存在しないことを示します。+++ b/new_file.txt
は、追加された新しいファイルを示します。- チャンクヘッダーの
-0,0
は、元のファイルに差分に関わる行がないことを示します。+1,3
は、新しいファイルに1行目から3行の差分があることを示します。 +
で始まる行が、新しいファイルの内容です。
ファイルが作業コピーから削除された場合、そのファイル全体が「削除された内容」として表示されます。
diff
--- a/deleted_file.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This file will be deleted.
-Line 2.
-Final line.
--- a/deleted_file.txt
は、変更前のファイルを示します。+++ /dev/null
は、変更後のファイルが存在しないことを示します。- チャンクヘッダーの
-1,3
は、元のファイルに1行目から3行の差分があることを示します。+0,0
は、変更後のファイルに差分に関わる行がないことを示します。 -
で始まる行が、削除されたファイルの内容です。
このように、svn diff
の基本的な出力形式を理解することは、差分情報を正確に読み取る上で非常に重要です。
svn diff
コマンドの主要なオプション詳細
svn diff
コマンドはそのままでも便利ですが、様々なオプションを組み合わせることで、より柔軟かつ強力な比較が可能になります。ここでは、よく利用される主要なオプションを詳しく解説します。
リビジョン指定に関するオプション
差分を確認する際に、作業コピーのHEAD以外と比較したり、リポジトリ上の特定のリビジョン間を比較したりすることがよくあります。これには主に -r
と -c
オプションを使用します。
-r <リビジョン>
または --revision <リビジョン>
これは「作業コピー」と「指定したリビジョン」との差分を表示します。
bash
$ svn diff -r 100 myfile.c
このコマンドは、作業コピーの myfile.c
と、リポジトリのリビジョン100における myfile.c
の内容を比較します。作業コピーでリビジョン100以降に行われた変更が表示されます。
パスを省略した場合、作業コピー全体とリポジトリの指定リビジョンとの差分が表示されます。
bash
$ svn diff -r 100
これは、作業コピー全体とリポジトリのリビジョン100の状態を比較します。
BASE
, COMMITTED
, PREV
, HEAD
, WORKING
といったキーワードもリビジョンとして指定できます。
BASE
: 作業コピーの項目が最後に更新またはチェックアウトされた時のリビジョン。
bash
$ svn diff -r BASE myfile.c # 作業コピーのmyfile.cと、最後に更新した時のmyfile.cの差分COMMITTED
: 作業コピーの項目が最後にコミットされた時のリビジョン。PREV
:COMMITTED - 1
。最後のコミットの1つ前のリビジョン。HEAD
: リポジトリの最新リビジョン。WORKING
: 作業コピーの編集中のローカル状態。これはsvn diff
のデフォルトの比較対象です。
-r <リビジョン1>:<リビジョン2>
これは「リポジトリ上のリビジョン1」と「リポジトリ上のリビジョン2」の間の差分を表示します。作業コピーの状態は関係ありません。この形式でローカルのパスを指定すると、Subversionはまずそのパスに対応するリポジトリのパスを解決し、そのリポジトリパスについて指定された2つのリビジョン間の差分を取得します。
bash
$ svn diff -r 100:105 myproject/trunk
このコマンドは、リポジトリの myproject/trunk
ディレクトリについて、リビジョン100とリビジョン105の間の差分を表示します。リビジョン101から105までの間にそのディレクトリ内でコミットされたすべての変更内容(ファイルの追加・削除・変更、プロパティ変更など)がまとめて表示されます。
パスを省略し、リポジトリのURLを指定することもできます。
bash
$ svn diff -r 100:105 http://example.com/svn/myproject/trunk
URLを指定することで、作業コピーがなくてもリポジトリ間の差分を確認できます。
リビジョン指定において、片方を省略することも可能です。
svn diff -r 100:HEAD URL
: リビジョン100からHEADまでの差分svn diff -r BASE:HEAD path
: 作業コピーのBASEリビジョンからHEADまでの差分 (BASE以降、HEADまでの間にリポジトリで行われた変更を作業コピーに取り込んだ際の差分に相当)svn diff -r BASE:WORKING path
: これはsvn diff path
と同じ意味です。作業コピーのBASEリビジョンとWORKING状態の差分。
-c <リビジョン>
または --change <リビジョン>
これは、特定の1つのコミットに含まれる変更内容を表示するための便利なショートカットです。svn diff -r N-1:N URL
と同じ意味になります。
bash
$ svn diff -c 105 http://example.com/svn/myproject/trunk
このコマンドは、リビジョン105のコミットで myproject/trunk
ディレクトリ(とその配下)に加えられた変更を表示します。リビジョン104の状態とリビジョン105の状態の差分です。
パスを省略し、単にリポジトリのURLを指定することもできます。
bash
$ svn diff -c 105 http://example.com/svn/myproject
この場合、リポジトリ全体の、リビジョン105のコミットに含まれる変更が表示されます。
ローカルの作業コピーで -c
オプションを使う場合は、その作業コピーがどのリポジトリを指しているかをSubversionが判断して差分を表示します。
bash
$ svn diff -c 105 # 現在の作業コピーが対応するリポジトリパスについて、リビジョン105の変更を表示
-c
オプションは、リビジョン範囲を指定するよりも直感的に「このコミットの変更を見たい」という目的に合致します。複数のリビジョンを指定することも可能ですが、その場合は -c 103,105
のようにカンマ区切りではなく、複数回オプションを指定します (svn diff -c 103 -c 105 URL
)。この場合、指定されたすべてのリビジョンにおける変更がまとめて表示されます。
パス指定に関するオプション
svn diff
の引数として指定するパスは、作業コピー内のローカルパスであることも、リポジトリのURLであることも可能です。
- ローカルパスのみ:
svn diff path1 path2
- 通常、これは
svn diff -r BASE:WORKING path1
とsvn diff -r BASE:WORKING path2
を表示するわけではありません。 svn diff path1 path2
の形式は、実際にはsvn diff -r COMMITTED path1 path2
と同じ動作になります。つまり、ローカルのpath1
とpath2
を比較するのではなく、それぞれのパスが最後にコミットされた状態を比較します。これは非常に混乱しやすい挙動なので注意が必要です。一般的には、ローカルの変更を確認する場合は引数なし (svn diff
) またはsvn diff path
の形式を使用します。
- 通常、これは
- URLのみ:
svn diff URL1 URL2
- これは、リポジトリ上の2つのパスを比較します。パスはファイルでもディレクトリでも構いません。通常、同じリビジョンを指定して比較します。
bash
$ svn diff http://example.com/svn/repo/trunk http://example.com/svn/repo/branches/mybranch
これは、trunkのHEADリビジョンとmybranchのHEADリビジョンの間の差分を表示します。
- これは、リポジトリ上の2つのパスを比較します。パスはファイルでもディレクトリでも構いません。通常、同じリビジョンを指定して比較します。
- URLとローカルパス:
svn diff URL path
- これは、リポジトリ上のURLとローカルの作業コピーパスを比較します。
bash
$ svn diff http://example.com/svn/repo/trunk/myfile.c myfile.c
これは、リポジトリのtrunkにある最新版のmyfile.c
と、ローカルの作業コピーにあるmyfile.c
を比較します。svn diff -r HEAD myfile.c
と同じ意味になります。
- これは、リポジトリ上のURLとローカルの作業コピーパスを比較します。
基本的には、作業コピーの変更を確認する場合はローカルパスを指定し、リポジトリ上の履歴を確認する場合はリビジョンとURLまたは対応する作業コピーパスを指定すると考えると分かりやすいでしょう。
外部差分ツールに関するオプション
Subversionはデフォルトでテキストベースの差分表示を行いますが、GUIの差分/マージツール(meld, kdiff3, WinMergeなど)と連携することで、より視覚的に差分を確認できます。
--diff-cmd <プログラム>
使用する外部差分プログラムを指定します。
bash
$ svn diff --diff-cmd meld myfile.c
このコマンドを実行すると、Subversionは meld
プログラムを呼び出し、作業コピーの myfile.c
とそのBASEリビジョンの内容を比較させます。
-x <diff_options>
外部差分プログラムに渡すオプションを指定します。例えば、空白文字の変更を無視するオプションなどを外部ツールに渡したい場合に利用します。
bash
$ svn diff -x --ignore-space-change --diff-cmd meld myfile.c
ここで -x --ignore-space-change
は、meld
コマンドに対して --ignore-space-change
オプションを渡すことを意味します。具体的なオプション名は使用する外部ツールによって異なります。
--internal-diff
外部差分ツールの設定がされている場合でも、強制的にSubversion内蔵の差分プログラムを使用させます。
bash
$ svn diff --internal-diff myfile.c
このオプションは、.subversion/config
ファイルで diff-cmd
が設定されている場合に便利です。
表示内容に関するオプション
表示される差分の内容や形式を調整するためのオプションです。
--summarize
差分の詳細な内容(変更された行)は表示せず、変更があったファイルやディレクトリとその種類(追加、削除、変更、競合など)の要約のみを表示します。多数のファイルに変更があった場合に、全体像を把握するのに便利です。
bash
$ svn diff --summarize
出力例:
A trunk/new_file.txt
M trunk/src/main.c
D trunk/old_docs/
A
: 追加 (Added)M
: 変更 (Modified)D
: 削除 (Deleted)C
: 競合 (Conflicted)R
: 置換 (Replaced)I
: 無視 (Ignored – ただし diff には通常表示されない)
--no-diff-added
, --no-diff-deleted
作業コピーに追加されたファイル(A
状態)や削除されたファイル(D
状態)の内容差分表示を抑制します。大量のファイルを追加/削除した場合に、その内容ではなくリストだけ確認したい場合に便利です。
bash
$ svn diff --summarize --no-diff-added --no-diff-deleted
このコマンドは、追加・削除されたファイルは --summarize
でリスト表示されますが、svn diff
本来の出力としてそれらのファイルの内容差分は含まれません。変更されたファイル (M
状態) の内容は通常通り表示されます。
--ignore-whitespace
, --ignore-eol
, --ignore-all-space
空白文字や行末の違いを差分として無視します。コードのフォーマット変更などが大量にある場合に、実質的なコード変更だけを確認したい場合に役立ちます。
--ignore-whitespace
: 行頭・行末の空白の増減、行内の連続する空白の増減を無視します。--ignore-eol
: 行末コード(LF, CR+LF)の違いを無視します。異なるOS間でファイルをやり取りした場合などに発生する差分を無視できます。--ignore-all-space
: すべての空白文字(行頭、行末、行内)の増減・変更を完全に無視します。
bash
$ svn diff --ignore-all-space myfile.c
これは、myfile.c
の内容について、空白文字のみが異なる行を差分として表示しないようにします。
これらのオプションは、外部diffツールに渡す -x
オプションとして使用されることもありますが、Subversion内蔵のdiff機能でもこれらのオプションを直接使用できます。
--properties
, --no-properties
デフォルトでは、svn diff
はファイルの内容の差分と、プロパティの差分(svn:ignore
, svn:keywords
など)の両方を表示します。
--properties
: プロパティの差分のみを表示します。ファイル内容の差分は表示されません。
bash
$ svn diff --properties mydirectory/
これは、mydirectory/
またはその配下の項目でプロパティが変更されたもののリストと、具体的なプロパティの変更内容を表示します。--no-properties
: プロパティの差分表示を抑制します。ファイル内容の差分のみが表示されます。
bash
$ svn diff --no-properties myfile.c
プロパティの差分は、ファイル内容の差分とは異なる形式で表示されます。例えば、svn:executable
プロパティを追加した場合などは以下のように表示されます。
“`diff
— my_script.sh (リビジョン 12345)
+++ my_script.sh (作業コピー)
Property changes on: my_script.sh
Added: svn:executable
+ *
“`
--xml
出力をXML形式にします。これは人間が直接読むよりも、プログラムが解析するために利用されます。
bash
$ svn diff --xml > diff_output.xml
XML形式の出力構造は複雑ですが、機械的な処理には適しています。
その他のオプション
--force
通常、svn diff
はコピーや移動のソースとなっている項目や、競合している項目の差分を表示しない場合がありますが、--force
オプションを使用するとこれらの項目も含めて強制的に差分を表示しようとします。
--changelist <リスト名>
作業コピー内のファイルやディレクトリを特定の「チェンジリスト」に登録している場合、そのチェンジリストに含まれる項目のみを対象に diff を実行します。
bash
$ svn diff --changelist my-feature-work
これは、チェンジリスト my-feature-work
に登録されている項目のみの差分を表示します。特定のタスクに関連する変更だけを確認したい場合に便利です。
--depth <タイプ>
ディレクトリを指定した場合に、どの深さまで差分を再帰的に表示するかを制御します。
empty
: ディレクトリ自体のプロパティ変更のみ(内容は含まない)files
: ディレクトリ直下のファイルの変更のみ(サブディレクトリは含まない)immediates
: ディレクトリ直下のファイルとサブディレクトリのプロパティ変更(サブディレクトリの内容は含まない)infinity
: 指定ディレクトリ以下のすべての項目(デフォルト)
bash
$ svn diff --depth files mydirectory/
これは、mydirectory/
直下のファイルのみの差分を表示し、サブディレクトリ内の変更は無視します。
--limit <数>
(XML出力時のみ)
XML出力の際に、差分を表示するファイル数の上限を指定します。非常に大規模なリポジトリで差分をとる際に、出力が膨大になるのを防ぐために使用されることがありますが、あまり一般的ではありません。
bash
$ svn diff --xml --limit 100 > limited_diff.xml
さまざまな比較シナリオと svn diff
の使い方
svn diff
は、比較したい対象(作業コピー、特定のリビジョン、リポジトリ上のパス)と、比較したい範囲(ファイル、ディレクトリ、リビジョン範囲)を適切に指定することで、多岐にわたるシナリオに対応できます。ここでは、具体的なユースケース別に svn diff
の使い方を解説します。
シナリオ1:ローカルでの作業内容を確認する
最も一般的なケースです。コミットする前に、自分が作業コピーで行った変更内容を最終確認します。
コマンド:
bash
$ svn diff
解説:
引数なしの svn diff
は、作業コピーのローカル状態 (WORKING) と、その作業コピーが最後に更新/チェックアウトされた時点のリポジトリの状態 (BASE) との差分を表示します。これにより、手元の変更すべてが確認できます。
特定のファイルやディレクトリに限定したい場合は、パスを指定します。
bash
$ svn diff src/main.c
$ svn diff docs/
応用:
* 特定のチェンジリストの変更のみ確認: svn diff --changelist my-task-123
* 空白や行末コードの変更を無視して確認: svn diff --ignore-whitespace --ignore-eol
* 変更されたファイルの一覧だけ確認: svn diff --summarize
シナリオ2:作業コピーとリポジトリの最新版を比較する
他の人がコミットした最新のリビジョンを取り込む前に、自分の変更がリポジトリのHEADとどう違うかを確認したい場合があります。
コマンド:
bash
$ svn diff -r HEAD
解説:
これは、作業コピーのローカル状態 (WORKING) と、リポジトリの最新状態 (HEAD) との差分を表示します。svn diff
(WORKING vs BASE) とは異なる差分が表示される可能性があります。特に、他の開発者があなたの作業コピーを更新する前にコミットした場合に、このコマンドはローカルの変更 と リモートでの変更 の両方 が含まれた差分(ただし、ローカルのファイルとHEADのファイルの単純比較)を表示するため、競合が発生しうる箇所などを特定するのに役立ちます。
より正確には、作業コピーを一旦更新(svn update
)した場合の変更内容を確認したい場合は、更新前に svn diff -r HEAD
を実行し、更新後に svn status
や svn diff
を実行して競合などが発生していないか確認するのが一般的です。
シナリオ3:過去の特定リビジョンとの差分を確認する
特定の機能を追加する前(例えばリビジョンN)の状態と、現在の作業コピーの状態を比較したい。
コマンド:
bash
$ svn diff -r N [PATH]
解説:
これは、作業コピーのローカル状態 (WORKING) と、指定されたリビジョン N におけるファイル/ディレクトリの状態を比較します。例えば svn diff -r 150 src/feature.c
は、現在の src/feature.c
が、リビジョン150の時の src/feature.c
からどのように変更されたかを表示します。
シナリオ4:あるコミットがもたらした変更内容を確認する
リビジョン M でコミットされた変更が具体的に何かを知りたい。これはコードレビューなどでよく使われます。
コマンド:
bash
$ svn diff -c M [URL or PATH]
または
bash
$ svn diff -r M-1:M [URL or PATH]
解説:
-c M
オプションは、リビジョン M のコミットに含まれる変更を表示します。これはリビジョン M の一つ前のリビジョン (M-1) とリビジョン M の間の差分を取得することで実現されます。
- 作業コピー内で実行する場合:
svn diff -c 200
(現在の作業コピーが対応するリポジトリパスについて、リビジョン200の変更を表示) - リポジトリURLを指定する場合:
svn diff -c 200 http://example.com/svn/repo/trunk
(trunkの、リビジョン200の変更を表示)
-r M-1:M
の形式でも同じ結果が得られます。svn diff -r 199:200 http://example.com/svn/repo/trunk
シナリオ5:あるリビジョン範囲内のすべての変更をまとめて確認する
機能Aが導入されたリビジョン N から、機能Bが導入されたリビジョン M までの間に、プロジェクト全体(または特定のディレクトリ)がどのように変化したのかを確認したい。
コマンド:
bash
$ svn diff -r N:M [URL or PATH]
解説:
これは、リビジョン N の状態とリビジョン M の状態の差分を表示します。このリビジョン範囲 (N+1 から M まで) でコミットされたすべての変更内容が、まとめて1つの差分として表示されます。
例: svn diff -r 180:200 http://example.com/svn/repo/trunk/src
は、trunkのsrcディレクトリについて、リビジョン180の状態からリビジョン200の状態までの間に発生したすべての変更(ファイルの追加・削除・変更、プロパティ変更)をまとめて表示します。
シナリオ6:タグやブランチ間の差分を確認する
特定のリリースを示すタグと現在の開発ブランチ、あるいは異なるフィーチャーブランチ間で、どのような違いがあるかを確認したい。
コマンド:
bash
$ svn diff URL1 URL2
解説:
この形式は、リポジトリ上の異なる2つのパス(多くの場合、異なるブランチやタグのHEADリビジョン)を比較します。
例:
bash
$ svn diff http://example.com/svn/repo/tags/release-1.0 http://example.com/svn/repo/trunk
これは、release-1.0
タグのHEADリビジョンと、trunk
ブランチのHEADリビジョンの間の差分を表示します。タグがブランチの特定のリビジョンを指している場合、これは実質的に「タグ付けされたリビジョン」と「現在のtrunkのHEADリビジョン」の比較になります。
特定のファイルやディレクトリを指定することもできます。
bash
$ svn diff http://example.com/svn/repo/tags/release-1.0/src/main.c http://example.com/svn/repo/trunk/src/main.c
シナリオ7:差分をファイルに保存し、パッチとして利用する
自分のローカルでの変更内容を、他の開発者に共有したり、別の作業コピーに適用したりするために、「パッチファイル」として出力したい。
コマンド:
bash
$ svn diff > my_changes.patch
解説:
svn diff
の標準出力をファイルにリダイレクトすることで、Unified Diff Formatのパッチファイルを作成できます。このファイルには、現在の作業コピーで行われた変更内容(WORKING vs BASE/HEAD)が記録されます。
リポジトリ間の差分をパッチとして出力することも可能です。
bash
$ svn diff -r 100:105 http://example.com/svn/repo/trunk > r100-to-r105.patch
作成したパッチファイルは、patch
コマンド(Unix/Linux/macOSの場合)や svn patch
コマンド(Subversion 1.6以降)を使用して他の作業コピーに適用できます。
patch -p0 < my_changes.patch
またはpatch -p1 < my_changes.patch
(patchコマンドのオプションはパッチファイルの形式による)svn patch my_changes.patch [作業コピーのパス]
(Subversionのバージョンによってはフルパスが必要)
シナリオ8:プロパティの変更のみを確認する
ファイルの内容ではなく、svn:ignore
や svn:executable
、svn:mime-type
などのプロパティがどのように変更されたかだけを確認したい。
コマンド:
bash
$ svn diff --properties [PATH]
またはリビジョンを指定して:
bash
$ svn diff -r N:M --properties [URL or PATH]
解説:
--properties
オプションを使用すると、ファイルの内容差分は表示されず、プロパティの追加、削除、変更のみが表示されます。これは、特定のファイルやディレクトリのプロパティ設定を確認・管理する際に便利です。
ファイル内容とプロパティの両方をデフォルトで表示し、プロパティのみ表示を抑制したい場合は --no-properties
を使用します。
シナリオ9:大規模な変更の概要を素早く把握する
プロジェクト全体で多数のファイルに変更があった場合に、具体的な差分内容を見る前に、どのファイルがどのように変更されたか(追加、変更、削除など)のリストだけを確認したい。
コマンド:
bash
$ svn diff --summarize [OPTIONS] [TARGETS]
解説:
--summarize
オプションは、変更の概要を簡潔なリスト形式で表示します。特に引数なしの svn diff --summarize
は、現在の作業コピーで変更、追加、削除、競合などがあるすべての項目をリストアップするのに非常に役立ちます。
他のオプションと組み合わせて使うことも多いです。
svn diff -r 100:105 --summarize URL
: リビジョン100から105の間で、リポジトリ上で変更があった項目をリストアップ。svn diff --summarize --depth files mydirectory/
:mydirectory/
直下のファイルのみで、変更があったものをリストアップ。
応用的な使い方とテクニック
svn diff
コマンドをさらに効果的に活用するための応用的な使い方やテクニックを紹介します。
外部Diff/Mergeツールの利用
テキストベースの svn diff
出力は多くの情報を効率的に表示しますが、視覚的に差分を確認したり、変更を対話的にレビューしたりするにはGUIツールが優れています。Subversionは外部のDiff/Mergeツールと連携する仕組みを持っています。
設定方法:
Subversionのユーザー設定ファイル(Unix/Linux/macOSの場合は ~/.subversion/config
, Windowsの場合は %APPDATA%\Subversion\config
)を編集します。
[helpers]
セクションを探し、diff-cmd
オプションに使用したい外部Diffツールのコマンドを指定します。
“`ini
[helpers]
diff-cmd = diff_program (diff, gdiff, etc.)
diff-cmd = meld
diff-cmd = kdiff3
diff-cmd = code –wait –diff ${base} ${mine} # VS Codeの場合の例
“`
diff-cmd
に指定するコマンド名は、そのツールがパス通っている必要があります。また、Subversionは指定されたツールを呼び出す際に、適切な引数(比較対象となるファイルのパスなど)を渡します。多くのツールは、basefile minefile
のように2つのファイルパスを引数として受け取ります。meld
, kdiff3
, WinMergeU.exe
などがよく使われます。
VS Code
のように、Diffツールとして機能するエディタを指定する場合は、一時ファイルパスのプレースホルダ (${base}
, ${mine}
など) を適切に指定する必要がある場合があります。これはツールやSubversionのバージョンによって異なります。
使い方:
設定ファイルで diff-cmd
を設定しておけば、通常通り svn diff
コマンドを実行するだけで、指定した外部ツールが起動して差分を表示してくれます。
bash
$ svn diff myfile.c # meldが起動して myfile.c の差分を表示
$ svn diff # meldが起動して変更された各ファイルの差分を順次表示
特定の svn diff
呼び出しでのみ外部ツールを使いたい、あるいは設定を一時的に上書きしたい場合は、前述の --diff-cmd
オプションを使用します。
bash
$ svn diff --diff-cmd kdiff3 another_file.txt
外部ツールを起動したくない場合は --internal-diff
オプションを使用します。
bash
$ svn diff --internal-diff myfile.c
注意点:
外部ツールは、Subversionが一時的に作成した比較用ファイルを開きます。これらのファイルを直接編集しても、作業コピーのファイルは変更されません。差分ツールはあくまで内容を確認するために利用します。
バイナリファイルの差分表示
Subversionは、テキストファイルの内容差分をUnified Diff Formatで表示しますが、バイナリファイル(画像ファイル、実行ファイル、オフィス文書など)については内容の差分を取ることができません。
svn diff
は、デフォルトではバイナリファイルが変更されていることを検知すると、そのファイルについて「バイナリファイルが変更されました (Cannot display: Binary files differ)」のようなメッセージを表示します。
Index: path/to/image.png
===================================================================
Cannot display: Binary files differ
バイナリファイルの内容差分をどうしても確認したい場合は、そのファイルの内容をリビジョンごとに抽出し、バイナリファイル専用の比較ツール(例: 画像比較ツール)で比較する必要があります。これは svn diff
コマンドの機能としては直接サポートされていませんが、svn cat
コマンドなどを使って特定リビジョンのファイルを取得し、それを外部ツールに渡すことで実現できます。
例: リビジョン100と現在の作業コピーにある image.png
を比較したい場合
bash
$ svn cat -r 100 http://example.com/svn/repo/trunk/image.png > image_r100.png
$ cp image.png image_working.png # 作業コピーのファイルを一時ファイルとしてコピー
$ binary_diff_tool image_r100.png image_working.png # バイナリ比較ツールで比較
$ rm image_r100.png image_working.png
大規模な差分への対処
プロジェクト全体で大規模な変更があった場合、svn diff
の出力は数万行、数十万行にも及ぶことがあります。このような場合、出力をそのままターミナルに表示すると扱いにくいことがあります。
対策:
--summarize
オプションの活用: まず--summarize
で変更ファイル一覧を確認し、全体像を把握します。
bash
$ svn diff --summarize- 出力をファイルにリダイレクト:
svn diff > large_diff.patch
のようにファイルに保存し、テキストエディタで開いて閲覧します。
bash
$ svn diff -r 100:HEAD http://example.com/svn/repo > full_history_diff.patch - パイプと連携:
grep
やless
などのコマンドと組み合わせて、必要な部分だけを抽出したり、ページング表示したりします。
bash
$ svn diff | less # ページング表示
$ svn diff | grep 'my_module/' # 特定ディレクトリの差分行のみ抽出
$ svn diff --summarize | grep '.c$' # 変更されたCファイルのみをリストアップ - 外部Diffツールの設定: GUIツールは、大規模な差分でもファイル単位でナビゲーションしやすく、全体像の把握や特定箇所への移動が容易です。
リポジトリURLとローカルパスの指定規則
svn diff
コマンドでリポジトリURLやローカルパスを指定する際の一般的な規則を理解しておくと、混乱を防げます。
- 比較対象がリポジトリ上の2点の場合: 常に少なくとも1つはURLまたは絶対パス (file://…) で指定する必要があります。2つ目をローカルパスで指定した場合、それはリポジトリ上の対応するパスとして解釈されます。リビジョン指定は
-r N:M
または-c N
の形式で行います。
bash
$ svn diff -r 100:105 http://example.com/svn/repo/trunk # URLのみ
$ svn diff -r 100:105 trunk/ # ローカルパスがリポジトリパスに解決される
$ svn diff http://example.com/svn/repo/branchA http://example.com/svn/repo/branchB # URL同士の比較 - 比較対象が作業コピーとリポジトリ上の1点の場合: 作業コピー側のパスはローカルパスで指定し、リポジトリ側のパスはURLまたは対応するローカルパス、そしてリビジョンを
-r N
または-c N
の形式で指定します。
bash
$ svn diff -r 100 myfile.c # 作業コピーの myfile.c と r100 の myfile.c を比較
$ svn diff -r HEAD http://example.com/svn/repo/trunk/myfile.c myfile.c # rHEAD の URL と作業コピーのパスを比較 (これもOK) - 比較対象が作業コピーのローカル状態の場合: リビジョンやURL指定は不要です。引数なし、またはローカルパスを指定します。
bash
$ svn diff # WORKING vs BASE
$ svn diff myfile.c # WORKING vs BASE の myfile.c
$ svn diff -r BASE myfile.c # WORKING vs BASE の myfile.c (明示的な指定)
$ svn diff -r WORKING myfile.c # WORKING vs BASE の myfile.c (WORKING指定も結局BASEと比較されることが多い)
前述のsvn diff path1 path2
はローカルパスを指定していますが、これはCOMMITTED
リビジョン同士の比較になるという特殊なケースなので注意が必要です。
混乱しやすい場合は、常に「何を」「何と」比較したいのかを明確にし、それに合ったリビジョン指定とパス指定の形式を選ぶことが重要です。特にリポジトリ上の過去の状態と比較したい場合は、-r N:M
または -c N
とURL/パスの組み合わせを、ローカルでの変更を確認したい場合は引数なしまたは -r BASE
とローカルパスの組み合わせを基本とすると良いでしょう。
svn diff
実行時の注意点
svn diff
コマンドを実行する上で、いくつか注意しておきたい点があります。
-
作業コピーの状態:
svn diff
(引数なし) は、未コミットの変更(M
,A
,D
状態など)の差分を表示します。- 競合 (
C
状態) があるファイルについては、svn diff
の出力形式が通常と異なる場合があります。競合マーカーが含まれた状態での差分が表示されることもあります。競合を解消する前に差分を確認する場合は注意が必要です。 - 無視リスト (
svn:ignore
) に登録されている項目や、ロックされている項目など、Subversionの管理対象外であったり特殊な状態にある項目は、デフォルトではsvn diff
の対象外となるか、特殊な表示になることがあります。
-
リビジョン指定:
-r N:M
でN > M
のようにリビジョンを逆順に指定すると、通常とは逆向きの差分(MからNへの変更を元に戻す差分)が表示されます。これは差分を元に戻すパッチを作成したい場合などに意図的に使用されることもありますが、通常は若いリビジョンから新しいリビジョンへ順方向に指定します。BASE
,HEAD
,WORKING
などのキーワードは、コマンドを実行する作業コピーや、比較対象としてURLが指定されているかによって指すリビジョンが変化するため、その意味を正確に理解しておく必要があります。
-
パフォーマンス:
- 非常に大規模なリポジトリや、長大なリビジョン範囲を指定して
svn diff
を実行すると、差分の計算に時間がかかり、大量の出力が生成される可能性があります。必要に応じて--summarize
やパス指定で範囲を絞る、出力をファイルにリダイレクトするなどの対策を検討してください。リポジトリがリモートにある場合は、ネットワーク帯域もパフォーマンスに影響します。
- 非常に大規模なリポジトリや、長大なリビジョン範囲を指定して
-
認証と権限:
- リポジトリ上のパスやリビジョンを指定して
svn diff
を実行する場合、リポジトリへのアクセス権限が必要です。認証が必要な場合はパスワードなどを求められます。権限がないリソースの差分を取ろうとするとエラーになります。
- リポジトリ上のパスやリビジョンを指定して
-
行末コードと文字エンコーディング:
- 異なるOSで作業している開発者が混在している場合、行末コード(CRLF vs LF)の違いが差分として表示されることがあります。これを無視したい場合は
--ignore-eol
オプションを使用します。 - ファイルの文字エンコーディングが混在している場合、Subversionが正しくテキストファイルとして扱えない可能性があります。特に Shift_JIS などASCII互換性の低いエンコーディングを使用している場合は注意が必要です。
svn:mime-type
プロパティやsvn:eol-style
プロパティを適切に設定することで、Subversionがファイルを適切に扱うように設定できます。
- 異なるOSで作業している開発者が混在している場合、行末コード(CRLF vs LF)の違いが差分として表示されることがあります。これを無視したい場合は
関連コマンド
svn diff
コマンドは単独でも強力ですが、他のSubversionコマンドと組み合わせて使うことで、さらにバージョン管理作業を効率化できます。
svn status
: 作業コピーでどのような変更が行われたかの概要(変更、追加、削除など)を確認できます。svn diff --summarize
と似ていますが、svn status
はリポジトリとの差分だけでなく、ローカルで管理対象外のファイルなども表示します。svn status
で変更ファイルを確認してから、svn diff <file>
で個別の差分を確認する、という流れはよく使われます。
bash
$ svn status
$ svn diff src/my_changed_file.c # statusでMだったファイルの詳細を確認svn log
: リポジトリの変更履歴を確認できます。特定のリビジョンのコミットメッセージや作者、日付などを確認し、興味のあるリビジョンを見つけたらsvn diff -c N
やsvn diff -r N:M
でその変更内容を詳細に確認する、という流れが一般的です。
bash
$ svn log -l 10 # 最新10件のコミットログを表示
$ svn diff -c 205 # logで確認したリビジョン205の変更内容を確認svn cat
: 特定のリビジョンにあるファイルの内容を標準出力に出力します。これを作業コピーのファイルと比較したり、外部ツールに渡したりするのに利用できます。
bash
$ svn cat -r 150 src/config.h > config_r150.h
$ diff config_r150.h src/config.h # r150のファイルと作業コピーのファイルを比較svn patch
:svn diff
コマンドで出力した差分ファイル(パッチファイル)を、作業コピーに適用するコマンドです。Subversion 1.6以降で利用可能です。
bash
$ svn diff > my_feature.patch
# ...別の作業コピーに移動...
$ svn patch my_feature.patch
これらのコマンドと svn diff
を適切に組み合わせることで、Subversionを使った開発ワークフローがよりスムーズになります。
まとめ
本記事では、Subversionにおける svn diff
コマンドについて、その基本から応用まで詳細に解説しました。
svn diff
は、単にファイル内容の差分を表示するだけでなく、様々なオプションや引数の組み合わせにより、以下のような多岐にわたる比較ニーズに応えることができる非常に強力なツールです。
- ローカルでの作業内容の確認 (
svn diff
,svn diff path
) - 過去のリビジョンとの比較 (
svn diff -r N path
) - 特定コミットの変更内容の確認 (
svn diff -c N URL/path
) - リビジョン範囲内の変更履歴の集約 (
svn diff -r N:M URL/path
) - ブランチやタグ間の比較 (
svn diff URL1 URL2
) - 変更ファイル一覧の取得 (
svn diff --summarize
) - プロパティ変更の確認 (
svn diff --properties
) - 差分をパッチファイルとして出力 (
svn diff > file.patch
)
また、外部Diffツールの利用設定、大規模な差分への対処法、バイナリファイルの扱い、そして実行時の注意点についても触れました。
svn diff
コマンドをマスターすることは、Subversionを利用したバージョン管理において、自分の変更を正確に把握し、他の開発者との協調を円滑に進め、そしてリポジトリの履歴を深く理解するための鍵となります。
最初は基本的な使い方から始め、徐々にオプションや複雑なシナリオでの利用に挑戦してみてください。この記事が、あなたの svn diff
コマンドの理解を深め、日々の開発作業の効率向上に役立つことを願っています。