テキストファイルの比較方法:Diff ツールとテクニック
テキストの比較は開発者にとって日常的なタスクです。コード変更のレビュー、設定のドリフトのデバッグ、ドキュメントのマージなど、diff 出力を理解することは不可欠です。このガイドでは、効果的なテキスト比較のためのアルゴリズム、ツール、テクニックを解説します。
Diff 出力の理解
クラシックな unified diff フォーマットは、2つのファイル間の変更を表示します:
--- original.txt
+++ modified.txt
@@ -1,5 +1,6 @@
Line 1: unchanged
-Line 2: removed text
+Line 2: modified text
+Line 2.5: added line
Line 3: unchanged
Line 4: unchanged
-Line 5: also removed
-で始まる行は削除された(オリジナルから)+で始まる行は追加された(変更後のバージョンで)(スペース)で始まる行は変更のないコンテキスト@@マーカーは影響を受ける行番号を示す
Diff アルゴリズム
Myers アルゴリズム
Git やほとんどの diff ツールで使用されるデフォルトアルゴリズム。最短編集スクリプト — 一方のファイルを他方に変換するための最小限の挿入と削除を見つけます。ほとんどのコンテンツに対してクリーンで読みやすい diff を生成します。
Patience Diff
ソースコードのような構造化されたテキストに適しています。最短編集を見つける代わりに、まず両方のファイルに出現するユニークな行をマッチングし、次にそれらの間のセクションを diff します。これにより、論理的なコードブロックに沿った、より意味のある diff が生成されることがよくあります。
git diff --patience
Histogram Diff
Patience diff の改良版で、Git のバージョン 2.x 以降のデフォルトとして使用されています。繰り返しのある行をより適切に処理し、大幅な構造変更を持つファイルに対してよりクリーンな出力を生成します。
オンラインでのテキスト比較
ツールをインストールせずに素早く比較するには、Text Diff Checker がブラウザ内で直接サイドバイサイドおよびインライン diff ビューを提供します。2つのテキストを貼り付けると、変更がすぐにハイライトされます — すべての処理はローカルで行われます。
コマンドライン Diff ツール
diff (POSIX)
クラシックな Unix ツール:
# Unified フォーマット(最も読みやすい)
diff -u file1.txt file2.txt
# サイドバイサイド
diff -y file1.txt file2.txt
# 空白を無視
diff -w file1.txt file2.txt
# 再帰的なディレクトリ比較
diff -r dir1/ dir2/
git diff
Git リポジトリの外でも、git diff は優れた出力を提供します:
# 2つのファイルを比較
git diff --no-index file1.txt file2.txt
# 単語レベルの diff(行全体ではなく変更された単語をハイライト)
git diff --word-diff
# 統計サマリー(変更されたファイル、挿入、削除)
git diff --stat
colordiff / delta
カラーターミナル出力用:
# colordiff: diff のドロップイン代替
colordiff file1.txt file2.txt
# delta: Git 用のモダンな diff ビューア
git diff | delta
コードレビューのための Diff
効果的なコードレビューは読みやすい diff に依存します。diff の品質を向上させるテクニックを紹介します:
1. コミットを焦点を絞ったものにする
数百行にわたる大きな diff はレビューが困難です。各コミットは1つの関心事に対処すべきです:
- フォーマット変更とロジック変更を分離する
- 大規模なリファクタリングをインクリメンタルなステップに分割する
- ファイルの移動とファイルの変更を別のコミットで行う
2. 単語レベルの Diff を使用する
行レベルの diff は、長い文字列に小さな変更が埋もれている場合、実際の変更を隠します:
# 行全体ではなく、変更された単語のみを表示
git diff --word-diff
3. レビューで空白を無視する
フォーマット変更は意味のある diff にノイズを追加します:
git diff -w # すべての空白変更を無視
git diff -b # 空白の量の変更を無視
4. コンテキストを含めてレビューする
より多くのコンテキスト行は、周囲のコードを理解するのに役立ちます:
git diff -U10 # 10行のコンテキストを表示(デフォルトは3)
マージコンフリクトの処理
Git が競合する変更に遭遇すると、ファイルにコンフリクトをマークします:
<<<<<<< HEAD
const timeout = 5000;
=======
const timeout = 10000;
>>>>>>> feature-branch
解決するには:
- 両方の変更を理解する — それぞれなぜ行われたのか?
- どちらのバージョンを保持するか決めるか、または組み合わせる
- コンフリクトマーカーを削除する
- 結果をテストする
複雑なマージには、共通の祖先と両バージョンを並べて表示する三方向マージツールを使用してください。
非テキストコンテンツの比較
JSON Diff
標準的なテキスト diff は JSON では苦戦します。キーの順序やフォーマット変更がノイズを生むためです。セマンティック JSON diff は実際のデータ構造を比較します。構造的な比較には JSON Diff ツール をご覧ください。
CSV Diff
テーブルデータには列を認識する比較が必要です。標準の diff は各行を文字列として扱い、セルレベルの変更を見逃します。
バイナリファイル
Diff はバイナリファイルを意味のある形で比較できません。画像にはビジュアル diff ツールを使用してください。ドキュメントの場合は、まずテキストに変換するか、フォーマット固有の比較ツールを使用してください。
自動化での Diff
CI/CD パイプライン
テストで期待される出力を検証するために diff を使用:
command_under_test > actual_output.txt
diff expected_output.txt actual_output.txt
# 終了コード 0 = 同一、1 = 異なる
設定ドリフトの検出
本番環境の設定を期待される状態と比較:
diff deployed_config.yaml expected_config.yaml
ドキュメント変更の追跡
レビュー用にドキュメントの変更を追跡:
git diff --stat HEAD~5..HEAD -- docs/
FAQ
diff 出力の "hunk" とは何ですか?
hunk は diff 内の連続する変更ブロックです。各 @@ 行が新しい hunk を開始します。Git は近接する変更を単一の hunk にグループ化します — 2つの変更が3行以内(デフォルトのコンテキスト)にある場合、同じ hunk に表示されます。hunk は git add -p を使用して個別にステージできます。
Git で2つのブランチを比較するには?
git diff branch1..branch2 を使用して、2つのブランチ間のすべての差異を表示します。--stat でサマリーを追加するか、-- path/to/file で特定のファイルを比較します。ブランチが分岐してから追加されたものを比較するには、3つのドットを使用します:git diff branch1...branch2。
関連リソース
- Text Diff Checker — ブラウザでテキストをサイドバイサイドで比較
- JSON Diff デバッグガイド — JSON データの構造的比較
- 正規表現チートシート — 特定の変更を見つけるためのパターンマッチング