2つのファイルが「内容は同じなのに」diff が大量に出る場合、その多くは空白が原因です。エディタが行末の空白を削除した、タブをスペースに置き換えた、インデント幅を変えた、といったケースです。diff ツールにはこうした違いを無視するオプションがありますが、オプションごとに無視する範囲が違うため、正確に理解して使う必要があります。
GNU diff の空白関連オプション
| オプション | 長い名前 | 無視するもの |
|---|---|---|
-Z | --ignore-trailing-space | 行末の空白 |
-E | --ignore-tab-expansion | タブをスペースに展開したことによる違い |
-b | --ignore-space-change | 空白の量の変化、行末の空白 |
-w | --ignore-all-space | すべての空白 |
-B | --ignore-blank-lines | 空行だけの追加・削除 |
-i | --ignore-case | 大文字小文字 |
--strip-trailing-cr | 入力行末の CR 文字 |
git diff の対応オプション
git のドキュメントでは次のように説明されています。
--ignore-cr-at-eol:比較の際、行末のキャリッジリターン(CR)を無視します。--ignore-space-at-eol:行末の空白の変化を無視します。-b、--ignore-space-change:空白の量の変化を無視します。行末の空白を無視し、それ以外の1つ以上連続する空白をすべて同じものとみなします。-w、--ignore-all-space:行を比較するときに空白を無視します。一方には空白があり、もう一方にはない場合の違いも無視します。--ignore-blank-lines:すべての行が空行である変更を無視します。
-b と -w の決定的な違い
この2つはよく混同されます。ポイントは、空白が「ある/ない」を区別するかどうかです。
| 左 | 右 | -b(空白の量を無視) | -w(すべての空白を無視) |
|---|---|---|---|
a b | a b | 同じ | 同じ |
a b | ab | 違う | 同じ |
x = 1 | x=1 | 違う | 同じ |
if (a) +行末の空白 | if (a) | 同じ | 同じ |
| タブ1つのインデント | スペース4つのインデント | 同じ | 同じ |
-b は空白のかたまりを1つに縮めて見るもので、-w は空白をすべて取り除いて見るものです。そのため -w は x = 1 と x=1、さらには int a と inta まで同じとみなします。
インデントに意味がある場合の危険
Python、YAML、Makefile のようにインデントが文法の一部であるファイルでは、空白無視オプションが実際の変更を隠してしまうことがあります。
if ready:
start()
notify()
if ready:
start()
notify()
2つ目では notify() が if 文の外に出て動作が変わっていますが、-w で比較すると空白がすべて取り除かれるため、違いが消えてしまいます。-b は行頭の空白が「ある」から「ない」に変わったので、違いとして検出します。ただし、インデントが4スペースから8スペースに変わってコードが1段内側のブロックに入った場合は、空白の量が変わっただけなので -b でも見えません。
確実なのは、インデントが重要なファイルは空白オプションをオフにして比較することです。空白オプションは「整形しただけの変更かどうか」を確かめる用途に使い、最終確認はオプションなしで行う習慣をつけると安全です。
空行無視(-B)の範囲
-B と git の --ignore-blank-lines は、空行だけで構成された変更を隠します。空行の追加がほかの実際の変更と同じハンクに混ざっている場合、その空行はそのまま表示されることがあります。段落間の空行の数を変えた文書や、コードフォーマッタが関数間の空行を調整した場合に役立ちます。
このサイトのオプションとの対応表
| このサイト | 近い GNU diff | 近い git diff |
|---|---|---|
| 空白:そのまま比較 | (オプションなし) | (オプションなし) |
| 空白:行末の空白を無視 | -Z | --ignore-space-at-eol |
| 空白:空白の量を無視 | -b | -b |
| 空白:すべての空白を無視 | -w | -w |
| 大文字小文字を無視 | -i | (該当なし) |
| 空行を無視 | -B に近い(空行を比較から除外) | --ignore-blank-lines に近い |
| 改行コードを正規化 | --strip-trailing-cr +最終改行の無視 | --ignore-cr-at-eol に近い |
このサイトの「空行を無視」は、空行を比較対象から完全に外し、薄い色で表示するだけです。また、無視オプションは行内ハイライトにも適用されるため、「空白の量を無視」をオンにすると、空白の数だけが違う部分は強調されません。
このツールで試す
テキスト比較ツールに上の表の例を入れ、空白オプションを1つずつ切り替えてみると違いがすぐにわかります。行末の CR やファイル末尾の改行といった「見えない差分」は 改行コードと見えない差分で、結果を patch として読む方法は unified diff の読み方で続けて読めます。