gitでインデント量以外の変更点を表示する


2011年 06月 11日

問題

バグフィックスなりリファクタリングなり何かをするため、
コード中の複数のブロックのインデントを変更するということは少なくありません。

例えば以下のようなコードがあるとしましょう:

private void UpdateData()
{
    var db = GetDatabaseConnection();

    data1.UpdateSomething();
    data2.UpdateSomething();
    data3.UpdateSomething();

    data1.Save(db);
    data2.Save(db);
    data3.Save(db);
}

このコードは一連のデータを更新してデータベースに保存しています。
しかしこの手の更新はデータの一貫性を保証するためにトランザクション内で実行されなければなりません。
という訳でこのコードは以下のように修正されるべきです:

private void UpdateData()
{
    var db = GetDatabaseConnection();

    db.BeginTransaction();
    try
    {
        data1.UpdateSomething();
        data2.UpdateSomething();
        data3.UpdateSomething();

        data1.Save(db);
        data2.Save(db);
        data3.Save(db);

        db.Transaction.Commit();
    }
    catch
    {
        db.Transaction.Rollback();
    }
    finally
    {
        db.EndTransaction();
    }
}

さて、コミットする前に git diff を実行して変更点をレビューすることにしましょう。
ところが残念なことに以下のような結果が得られます:

diff --git a/t.cs b/t.cs
index e4e18dd..53a3b56 100644
--- a/t.cs
+++ b/t.cs
@@ -2,11 +2,26 @@ private void UpdateData()
 {
     var db = GetDatabaseConnection();

-    data1.UpdateSomething();
-    data2.UpdateSomething();
-    data3.UpdateSomething();
+    db.BeginTransaction();
+    try
+    {
+        data1.UpdateSomething();
+        data2.UpdateSomething();
+        data3.UpdateSomething();

-    data1.Save(db);
-    data2.Save(db);
-    data3.Save(db);
+        data1.Save(db);
+        data2.Save(db);
+        data3.Save(db);
+
+        db.Transaction.Commit();
+    }
+    catch
+    {
+        db.Transaction.Rollback();
+        throw;
+    }
+    finally
+    {
+        db.EndTransaction();
+    }
 }

なんということでしょう。 git diff は正しく動作しているものの、
これでは本質的な変更点が何なのか全く分かりません!
ここでは一連の更新処理をトランザクションで括り、
さらに元々あった更新処理のインデントを調整しました。
本質的な変更的は前者であって後者ではありません。
しかしこの出力からは本質的な変更点を識別することは困難です。

解決

幸いなことに、 git diff にはこの問題に対処するための素晴らしいオプションがあります。
git diff -b または git diff --ignore-space-change を実行してみましょう。
以下のような結果が得られます:

diff --git a/t.cs b/t.cs
index e4e18dd..53a3b56 100644
--- a/t.cs
+++ b/t.cs
@@ -2,6 +2,9 @@ private void UpdateData()
 {
     var db = GetDatabaseConnection();

+    db.BeginTransaction();
+    try
+    {
     data1.UpdateSomething();
     data2.UpdateSomething();
     data3.UpdateSomething();
@@ -9,4 +12,16 @@ private void UpdateData()
     data1.Save(db);
     data2.Save(db);
     data3.Save(db);
+
+        db.Transaction.Commit();
+    }
+    catch
+    {
+        db.Transaction.Rollback();
+        throw;
+    }
+    finally
+    {
+        db.EndTransaction();
+    }
 }

素晴らしい! git diff --ignore-space-change はふつうの git diff と同じように動作しますが、
空白文字の量の変更については無視します。そのため、インデントに関する変更は無視されます。
このように本質的な変更点を確認したい場合にとても便利なオプションです。

補足

実のところ、これは git だけの機能というわけではありません。
diff コマンドにも -b オプションがありますし、
他のバージョン管理システムでも同様の機能が利用できます。