Gitにおいて、「git diff」はブランチ管理に必須コマンドとなっており、最もよく使うコマンドのひとつです。ファイルの比較・管理に始まる、git diff のよく使うオプションを覚え書きしました。
これであなたも git diff マスターに、ぐんと近づけると思います。
git diff の基本動作と、主要なオプション
まずはgit diffの基本の概念ですが、「git diff」の基本動作は「作業ツリーに行われた変更の表示」です。
そして、引数に「比較元」を指定できるのですが、もし比較元を指定しない場合は、デフォルトで、「インデックス」を比較元とし、 [インデックス] → [作業ツリー] と比較した際の差分を表示する事になります。
この基本的な動作仕様の認識が曖昧なまま使っている方も、少なくないのではないでしょうか。下記、最も主要な git diff の利用ケースを列挙します。
インデックスとの差分を見る
最も基本的な比較です。インデックスに対して作業ツリーで行った変更を見ますので、まだgit addしていない変更内容は、このコマンドで簡単にチェックできます。
// [インデックス] → [作業ツリー] の差分を見る git diff
最新のコミットとの差分を見る
「HEAD」は現在のブランチの先頭のコミットへの参照です。git diff の比較元に、コミットを指定することで、[そのコミット] → [作業ツリー] の差分を表示しますが、ここで「HEAD」と参照を指定すれば、当然、現在作業中のブランチの先頭(すなわち最新コミット)を間接的に指定する事になります。
// [最新コミット] → [作業ツリー] の差分を見る git diff HEAD
指定したコミットとの差分を見る
もちろん比較元の指定で、上述のような「HEAD」のような参照でなく、特定のコミットの識別子(SHA-1)を直接指定することで、[比較元] → [作業ツリー] の比較を行います。
// <commit> → [作業ツリー] の差分を見る git diff <commit>
インデックスとHEADの差分を見る
冒頭で、git diff の基本は「作業ツリー」に行われた変更を表示する、と言及しましたが、この動作を下記の「--cached」オプションを利用する事で、「インデックス(ステージ領域)への変更を見る」ようになます。
こちらは、git commit を行うの直前に「あれ?結局何を add したんだっけな〜」と確認するために非常によく使うコマンドです。ぜひ覚えてたくさん利用しましょう。
--cached 利用時は、引数で比較元を指定しなかった場合、デフォルトでHEADが比較元になります。
// [最新のコミット] → [インデックス] を比較する git diff --cached git diff --cached HEAD // 同義
git diff の比較対象の違いについて
上記で紹介した3つの比較です。下記の3種類は、git diff でもっともよく利用するコマンドといってよいでしょう。
やりたい事 | git diffコマンド |
インデックス → 作業ツリー | git diff |
HEAD → 作業ツリーの比較 | git diff HEAD |
HEAD → インデックス | git diff --cached |
さて、これらの違いは混乱しやすいので、図を使って少し詳しく見ていきます。
「diff」と「diff --cached」の比較対象の違い
さて、おさらいですが、
- 通常は比較元(デフォルトでインデックス)から作業ツリーへの差分
- --cachedで比較下(デフォルトでHEAD)からインデックスへの差分
を見るように動作します。図にすると以下のようなイメージです。
HEADは「作業中ブランチの先頭コミット」を指しますので、現在のコミットを作ろうとしている時、作業ツリーとインデックスの変更状況について分を調べたい時はもっぱら「git diff」「git diff --cached」「git diff HEAD」のいずれかを使うことになると思います。
インデックスと、コミットの関係
「インデックス」は「ステージ領域」とも呼ばれますが、この概念が Git 特有なので、入門者は非常に混乱しやい点だと思います。こちらについても少しまとめておきます。
まずは「インデックス」と「作業ツリー」の概念と、git add とgit commitの関係についてです。
「作業ツリー」は単純なファイルシステム上のファイルですが「インデックス」はGitが管理するバイナリファイルです。(.gitディレクトリ内にあるindexというファイルです。)
インデックスは将来的に(commit されれば)、正式なコミットになります。あえて図にすると、このようなイメージです。
上図で、作業ツリーの近くで汗をかいてがんばっているのは、もちろんあなたです。いつもお疲れ様です。
git diff のよく使うオプション
使用頻度はそれほどでもないですが、非常に便利な git diff のオプションをご紹介します。
ファイル名だけを表示する
差分が生じたファイルの、ファイル名の一覧を表示します。比較元(引数)は自由に指定できます。
// ファイル名だけを比較する git diff --name-only
比較するファイルを限定する
// 比較するファイルを限定する git diff <コミット名> <コミット名> ―― <ファイル名>
「ファイル名」と書きましたが、実際は「パス」(ディレクトリ名など)を指定して、比較する範囲を限定できます。
ついでに、似たような結果を得られるのがこちら:
// パスやファイル同士を比較する git diff <コミット名>:<ファイル名> <コミット名>:<ファイル名>
指定する<コミット名>の代わりに、<コミット名>:<ファイル名> とすることで、範囲を限定した参照を指定することができます。これを利用して、git diff においても、比較対象を限定するというケースですね。
ご参考まで、こちらはgit object の指定方法に関する参考文献です
特定のコミット間を比較する
さて、git diff では、比較元だけでなく、比較先を指定することもできます。これにより2種類のコミットのコミット間の比較を行うこともできます。
// コミット同士を比較する git diff [比較元のコミット] [比較先のコミット]
この場合、比較元 → 比較先 でなにが変更されたのかが、表示されます。(右から左に時系列がながれます)コミットの指定はコミットのID(SHA-1)、ブランチ名、HEAD(現在のブランチの先頭)など、特定識別子があれば大丈夫です。
直前のコミットの内容を表示
また、例えば、HEAD^など、「^」を使って1個前のブランチを比較するのはよく使います。こんな感じです。
// HEADの一個前 から HEADへの変化を表示 git diff HEAD^ HEAD
実際は、git show でよく似た効果が得られます。
// HEADのコミット内容を表示 git diff show // 同義 git diff show HEAD
上記は、HEADで指定されるコミットが、マージコミット(git merge から生成されたコマンド)でない事に注意して下さいね、git showの動作が異なってしまいます。git show の動作はまた別の機会に深掘りしましょう。
リモートブランチとローカルブランチの差分を比較
「特定のコミット同士の比較」の応用編です。リモートブランチからmasterをpull する前に「どのくらい先にすすんじゃったんだろ?」なんて、事前に調べたい時に使います。
git pull は、いうなれば「git fetch & git merge」ですので、いきなり git pull を実行すると、いきなりローカルブランチにマージがかかってしまいます。
これを事前にdiffで差分を確認します。イメージしやすいように、masterブランチの例で書くと・・・、
// リモートを取ってきて・・ git fetch origin master // [ローカル] → [リモート追跡]の差分を見る git diff master origin/master
git fetch、git merge の振る舞いに関して、もやっとしている人は、ぜひこちらの記事を御覧ください:
スペースを無視する
上記までは、オプションによる比較対象の設定でしたが、ここからは、表示の出力方法における設定のオプションです。
// ファイル内のスペースの数の違いを無視する git diff -b git diff --ignore-space-changes // ファイル内のスペースを完全に無視する git diff -w git diff --ignore-all-space
スペース(whitespace)だけの違いを、変更とみなさず、無視します。整形した行は表示しないでほしい時、ありますね。
前者の「b」は、行の末尾の空白と、1つ以上のスペースが連続しているとき、数の違いが発生して無視します。一方で、後者の「w」は、あらゆるスペースの有無と、スペースの数の差分を無視します。
w はスペースと言っていますが、改行コードの違い無視することもできます。
よく似ていますが、上記の仕様を覚えておけば、状況によって使い分けられそうですね。
文字レベルで違いを表示する
// 差分を文字レベルで表示する git diff --word-diff // 差分を文字レベルで表示する。色と+、ーだけで、差分を表現する git diff --word-diff=color // git diff HEAD --word-diff と同じ効果 git diff --color-words
git diff は、通常は行の差分を表示するのですが、文字レベルで違いを表示してくれます。これは細かい変更がある時便利です。
後者は「--word-diff=color」とモードしていをした時と同じです。文字の色が変わるだけになるので、こちらのほうが差分が見やすいです。
--word-diff=<モード> のオプションについて、利用可能なモードを抜粋しておきます:
word-diff のモード一覧
color
色だけを使って差分をハイライトする。plain (デフォルト)
単語の差分を、[-removed-]と[+added+]を使って表示する。デリミタが入力に発生してもエスケープしない。出力が曖昧になることがあるporcelain
単語の違いを新しい1行を使って表示する。(通常は行内で差分を表現するが、必ず1行でadd, removedを表現する、porcelainは、結構読みにくいです・・。)none
--word-diffを.gitconfigなどで強制している際に、word-diffをオフにするときに使う。
git diff --word-diff=plain の例
git diff --word-diff=color の例
変更が多く細かくなると、後者のほうが見やすい、かもしれませんね。
git diff の関連リンク
最後に git diff の参考リンクです。だいたい公式マニュアルが最強です。
また、基本的な設定ですが、git diff に色をつけるgitconfig設定に関してです。
さて、git diff に関しては、以上です。git diff は、非常によく利用するコマンドなので、正確に理解しておくとハッピーになれると思います。
それでは、楽しい Git ライフを。