手軽屋
ツール一覧

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-statusA/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 で固定できる。

コードレビュー実務での読み解き順

  1. git diff --stat main で規模感を把握(数十行か、数千行か)
  2. git diff --name-status main で A/M/D の内訳を確認
  3. git diff main -- '*.test.ts' でテストの変更を先に見る
  4. 本体実装の git diff main -- src/ をハンク単位で読む
  5. 気になる箇所は git log -p <file> でコミット粒度の意図を読む
  6. 不安があれば git blame -L <start>,<end> で過去の経緯を追う

読み間違えやすい落とし穴

  • 改行コードの一括変更(LF→CRLF)は全行差分に見える。.gitattributes での正規化が先
  • インデントだけの変更は -w--ignore-all-space で除外できるが、Python は意味が変わるので注意
  • バイナリ差分は Binary files differ しか出ない。テキスト差分が必要なら --text
  • サブモジュール差分はハッシュだけ表示。中身を見るには --submodule=diff