git diff の読み方とunified format実務
最終更新:2026年6月16日/一次情報:git-scm.com/docs/git-diff (Git 2.54.0), POSIX IEEE Std 1003.1-2017
git diff を最初に見たときの印象は「記号が多くて読みにくい」だ。けれど読み方を一度覚えると、PR のレビュー速度が劇的に上がる。本記事では「@@で囲まれた数字は何か」「先頭の + - は何を意味するか」「--stat と -p と --name-only の使い分け」を、Git公式マニュアル(git 2.54.0)と POSIX diff -u 仕様の一次情報に沿って整理する。
unified format の基本構造
git diff のデフォルト出力は POSIX diff -u 互換の unified format だ。1つの変更ファイルは「ヘッダ」「ハンク(hunk)」「行」の3層で表される。ヘッダは diff --git a/path b/path から始まり、ファイルモードや index ハッシュが続く。ハンクは @@ -L,N +L,N @@ という形式で、「変更前は L 行目から N 行」「変更後は L 行目から N 行」を意味する。ハンクの中の各行は先頭1文字で種別が決まる:スペースは「変更なし」、+は「追加」、-は「削除」だ。前後3行ずつのコンテキスト(既定値)が含まれるため、変更行だけでなく周辺コードも見える。
よく使うオプション早見表
| オプション | 用途 |
|---|---|
--stat | ファイル単位の追加削除行数サマリ。PR全体の規模把握に |
--name-only | 変更ファイル名のリストだけ。スクリプト連携用 |
--name-status | A/M/D(追加/変更/削除)とファイル名。CI判定に |
-U <n> | コンテキスト行数を変更(既定3)。コードレビューは5前後が便利 |
--word-diff | 単語単位の差分。文章ファイルのレビューに最適 |
-M | ファイル名変更(rename)を検出。-M50% で類似度しきい値 |
--no-color | パイプ・コピペ用にANSIエスケープを除去 |
rename と combined diff
ファイル名の変更(リネーム)は Git が内容類似度から自動検出する。similarity index 95% や rename from / rename to のヘッダが付き、変更がなければハンクは省略される。マージコミットを git show したときに現れる combined diff は、複数の親コミットそれぞれとの差分を1つにまとめた形式で、ハンク先頭が @@@ のように3つになり、各行の先頭も2文字(親ごとの+/-/スペース)になる。マージ後のレビューで「どちらの親から来た変更か」を見るときに有用だ。
format-patch とメール送信
git format-patch -1 はコミットを mailbox 形式のパッチファイルに変換する。From / Subject / 本文 / unified diff の順で並ぶ。git am で取り込めばコミットメッセージごと適用できる。Linux カーネルや Git 本体のように「メーリングリストでパッチをやりとりする」プロジェクトでは今でも現役のフローだ。
アルゴリズム選択:myers / minimal / patience / histogram
--diff-algorithm=myers(既定)は Eugene Myers の1986年論文に基づくO(ND)アルゴリズム。minimal は最小編集距離を厳密に求めるが遅い。patience は一意な行をアンカーにする手法で、リファクタリングなど「同じ関数が移動した」ケースで読みやすい差分が出る。histogram は patience の改良版で速度と読みやすさのバランスが良い。チーム共通の好みがあれば git config diff.algorithm で固定できる。
コードレビュー実務での読み解き順
git diff --stat mainで規模感を把握(数十行か、数千行か)git diff --name-status mainで A/M/D の内訳を確認git diff main -- '*.test.ts'でテストの変更を先に見る- 本体実装の
git diff main -- src/をハンク単位で読む - 気になる箇所は
git log -p <file>でコミット粒度の意図を読む - 不安があれば
git blame -L <start>,<end>で過去の経緯を追う
読み間違えやすい落とし穴
- 改行コードの一括変更(LF→CRLF)は全行差分に見える。
.gitattributesでの正規化が先 - インデントだけの変更は
-wや--ignore-all-spaceで除外できるが、Python は意味が変わるので注意 - バイナリ差分は
Binary files differしか出ない。テキスト差分が必要なら--text - サブモジュール差分はハッシュだけ表示。中身を見るには
--submodule=diff