Gitでコミット間の差分を比較する方法|diff・show・format-patchの使い分けと実践シナリオ完全ガイド

Gitでコミット間の差分を比較する方法 Git

「バグを仕込んだコミットはどれだ?」「v1.2.0からv1.3.0で何が変わった?」「10コミット前と今で、どの関数が書き換わった?」——開発の振り返り・原因調査・リリースノート作成で、コミット間の差分を確認する場面は頻繁にあります。

この記事では、Gitで特定のコミット同士を比較する方法を体系的に解説します。SHA・タグ・HEAD~Nなど多彩なコミット参照、git diffgit showの使い分け、単一コミットを親と比較する書式、パッチファイル出力、そしてgit bisectgit log --followとの連携まで、調査・レビュー・リリース管理で役立つコマンドを網羅します。

この記事で学べること

  • コミットを指す8種類の参照記法(SHA・HEAD・HEAD~N・タグ・reflog など)
  • git diff <A> <B>の基本と表示オプションの使い分け
  • git showで単一コミットを親との差分で確認する方法
  • タグ同士の比較(リリース間の変更把握)
  • パッチファイルへの出力(format-patch/リダイレクト)
  • 特定ファイル・ディレクトリに絞ったコミット間diff
  • バグ調査・リリースノート作成・バックポート検討で使う実践シナリオ
スポンサーリンク

コミットを指す参照方法いろいろ

「コミットA」をコマンドに渡すとき、SHA(ハッシュ値)以外にも様々な指定ができます。目的に応じて使い分けると手早く比較が書けます。

記法 意味
SHA(省略可) コミットのハッシュ値 a1b2c3d(7文字以上)
HEAD 現在チェックアウト中の先端 HEAD
HEAD~N HEAD からN個前 HEAD~3(3つ前)
HEAD^ HEADの親(^=親コミット) HEAD^HEAD~1と同じ)
タグ 名前付きで固定された参照 v1.2.0
ブランチ名 そのブランチの先端コミット mainorigin/main
reflog参照 HEADの移動履歴から HEAD@{2}"HEAD@{yesterday}"
上流指定 追跡先の先端 @{u}@{upstream}

ポイント:SHAはコピペで確実ですが、人が読み書きするならHEAD~5やタグが直感的です。調査スクリプトなどではブレない参照(SHA・タグ)を使い、手動の検証では相対参照を活用するとスピードと安全性のバランスが取れます。

基本:git diff A B でコミット間を比較

2つのコミットを指定すれば、それぞれのツリー(スナップショット)を直接比較します。ブランチ間の2ドット(A..B)と同じ意味で、空白区切りでもドット付きでも結果は同じです。

コミット間の基本diff
# SHA指定
git diff a1b2c3d e4f5g6a

# 相対参照
git diff HEAD~5 HEAD

# タグ同士(v1.2.0 と v1.3.0 の差分)
git diff v1.2.0 v1.3.0

# 現在とN日前
git diff "HEAD@{yesterday}" HEAD

# ブランチの先端と固定コミット
git diff a1b2c3d main

# 2ドットは空白区切りと同義
git diff HEAD~3..HEAD

A..B と A…B の使い分け

  • A..B(2ドット):A と B の先端同士を直接比較(git diff A Bと同じ)
  • A...B(3ドット):merge-base と B の差分(PR相当の見え方)
  • コミット同士の比較は通常2ドット。3ドットが活きるのはブランチ間比較のときが多い
  • 詳細はブランチ間の差分を比較する方法を参照

単一コミットを確認する:git show

git showは指定コミット1つを「親コミットとの差分」として表示します。「このコミットが何をしたのか」を素早く見たいときに最適です。内部的にはgit diff <commit>^ <commit>と等価です。

git show の使い方
# 最新コミットを表示
git show

# 特定コミットを表示
git show a1b2c3d

# 相対指定
git show HEAD~2

# タグが指すコミットを表示
git show v1.2.0

# 特定ファイルの変更だけ
git show HEAD -- src/auth.py

# 変更行だけで統計
git show --stat HEAD

# メッセージを省略して差分だけ
git show --format= HEAD

# コミットメッセージだけ
git show -s --format=%B HEAD

ポイント:「このコミットで何が変わった?」を1コマンドで確認したいとき、git showが最も直感的です。git diff HEAD~1 HEADでも同じ結果ですが、コミットメッセージやメタ情報も同時に表示されるため、レビューではgit showが見やすいです。

親コミットとの差分を見る

「このコミット単体がリポジトリに何を加えたか」を確認する書き方は複数あります。挙動と読みやすさの両方で、好みの書式を選んでください。

親コミットとの比較
# パターン①: git show(最も簡潔)
git show a1b2c3d

# パターン②: 親(^)を明示指定
git diff a1b2c3d^ a1b2c3d

# パターン③: 相対参照で直前と比較
git diff HEAD~1 HEAD

# パターン④: 2ドット記法
git diff HEAD~1..HEAD

# パターン⑤: 親が複数(マージコミットの場合)
git show a1b2c3d^1   # 第1親
git show a1b2c3d^2   # 第2親

マージコミットの diff は注意

マージコミット(2つ以上の親を持つ)にgit showを使うと、デフォルトでは「結合された差分」(combined diff)が表示されます。片方の親だけと比較したい場合は^1^2で明示します。マージコミット打ち消しと合わせてmergeコミットを取り消して履歴を元に戻す方法も参照してください。

diff出力を目的別に整える

表示バリエーション
# ファイル名だけ列挙
git diff --name-only v1.2.0 v1.3.0

# 変更種別付き(A/M/D/R)
git diff --name-status v1.2.0 v1.3.0

# 変更規模(行数)を集計
git diff --stat v1.2.0 v1.3.0

# サマリーだけ1行で
git diff --shortstat v1.2.0 v1.3.0

# ワード単位の差分(文書・READMEに便利)
git diff --word-diff v1.2.0 v1.3.0

# 空白無視
git diff -w v1.2.0 v1.3.0

# 前後10行ずつコンテキスト
git diff -U10 v1.2.0 v1.3.0

# rename検出強化(大きな変更を伴ってもrenameと認識)
git diff -M50% v1.2.0 v1.3.0

特定ファイル・ディレクトリに絞り込む

パスで絞る
# 特定ファイル
git diff v1.2.0 v1.3.0 -- src/auth.py

# ディレクトリ
git diff v1.2.0 v1.3.0 -- src/

# globパターン
git diff v1.2.0 v1.3.0 -- "*.js" "*.ts"

# 除外指定
git diff v1.2.0 v1.3.0 -- . ":(exclude)tests/"

ファイル指定の詳細はgit diff でファイル指定する方法を参照してください。

パッチファイル(patch)として出力する

差分を他の環境に渡したり、メールでレビューを依頼したりするときはパッチファイル形式が便利です。git format-patchでコミット単位の綺麗なパッチ、リダイレクトで手軽な diff ファイル、と用途で使い分けます。

パッチファイルの生成
# 差分を単純ファイル化
git diff v1.2.0 v1.3.0 > release-1.2-to-1.3.patch

# コミット単位の整ったパッチ(mbox形式、git am で適用可)
git format-patch v1.2.0..v1.3.0
# → 0001-xxx.patch, 0002-xxx.patch ... が生成される

# 直近3コミットをパッチ化
git format-patch -3

# 出力先フォルダ指定
git format-patch v1.2.0..v1.3.0 -o patches/

# パッチを他リポジトリで適用(format-patch 経由)
git am patches/0001-xxx.patch
# 単純diffから適用
git apply release-1.2-to-1.3.patch

ポイント:format-patchはコミットメッセージ・作者情報を保持するため、別リポジトリに履歴を綺麗に移植できます。単純diffリダイレクトはファイル差分だけで、コミット情報は含まれません。目的に応じて選びましょう。

実践シナリオ

シナリオ① リリース間の変更を把握(リリースノート作成)

v1.2.0 から v1.3.0 の差分
# 変更ファイル一覧
git diff --name-status v1.2.0 v1.3.0

# コミットメッセージ一覧
git log --oneline v1.2.0..v1.3.0

# 規模感の集計
git diff --shortstat v1.2.0 v1.3.0

# 著者別コミット集計
git shortlog v1.2.0..v1.3.0

# 特定ディレクトリの変更だけ
git diff v1.2.0 v1.3.0 -- src/api/

シナリオ② バグ発生コミットの特定

bisectと組み合わせる
# 動いていた時点と壊れた時点を指定してbisect開始
git bisect start
git bisect bad HEAD
git bisect good v1.2.0

# Gitが中間コミットをcheckoutするので、動作確認
# 良ければ: git bisect good / 悪ければ: git bisect bad
# 繰り返すとバグ混入SHAが特定される

# 特定されたコミットの変更内容を確認
git show <混入SHA>

# 親との比較で原因コードを精査
git diff <混入SHA>^ <混入SHA> -- src/

# bisect終了
git bisect reset

bisectの詳しい使い方はbisectでバグを仕込んだコミットを特定する方法を参照。

シナリオ③ 回帰調査(regression の原因追跡)

特定ファイルの履歴を遡る
# 特定ファイルを触ったコミットだけ抽出
git log --oneline --follow -- src/auth.py

# 不具合発生前後で特定ファイルの変化を見る
git diff <疑わしいSHA>^ <疑わしいSHA> -- src/auth.py

# 該当関数を含む変更を検索
git log -S "authenticate" --oneline -- src/auth.py
# -S=pickaxe 検索:指定文字列の追加/削除を含むコミットを絞り込む

# その変更を確認
git show <SHA> -- src/auth.py

シナリオ④ バックポート前の下見

hotfixブランチから本線に戻す準備
# 本線と hotfix ブランチの差分コミット一覧
git log --oneline main..hotfix/urgent

# 取り込み候補の1コミットを精査
git show <SHA>

# 個別ファイルの diff でリスク評価
git diff main <SHA> -- src/critical.py

# 問題なければ cherry-pick
git switch main
git cherry-pick <SHA>

GUI・IDEでのコミット比較

主要ツールでの比較

  • VS Code / Cursor:GitLensのOpen Changes with...、Timelineビューで任意2点の比較
  • JetBrains:Gitログで2コミットをCtrl+選択 → Compare Versions
  • SourceTree:コミット2つをShift+選択 → 右側に差分表示
  • GitHub Webhttps://github.com/{user}/{repo}/compare/{SHA1}...{SHA2}
  • gitkgitk --allでGUIグラフ+クリックで差分表示
  • git difftool:お好みのGUI差分ツールを呼び出し可能

GitHub Web の compare URL

ブラウザで2コミット間を開く
# SHA同士 or タグ同士のURL形式
open "https://github.com/user/repo/compare/v1.2.0...v1.3.0"
open "https://github.com/user/repo/compare/a1b2c3d...e4f5g6a"

# 単一コミットを見るなら /commit/ 形式
open "https://github.com/user/repo/commit/a1b2c3d"

やってはいけない落とし穴

順序を逆にして「マイナス差分だらけ」と困惑する

git diff A Bは「AからBへの変更」を表示します。古いコミットを右に、新しいコミットを左に置くと、追加されたコードがマイナス扱いで出てきて混乱します。「古い→新しい」の順で書くのが自然です:git diff v1.2.0 v1.3.0(v1.2.0→v1.3.0の変化を見る)。

SHAを短くしすぎてambiguousエラー

3〜4文字ではリポジトリに複数のコミットがマッチすることがあります。fatal: ambiguous argument 'abc'が出たらgit log --onelineで表示される7〜8文字を使うのが安全です。大規模プロジェクトでは10文字以上を推奨。

merge commit の diff で混乱する

マージコミットには親が2つあるため、git showのデフォルト動作は「combined diff」という特殊な表示になります。通常のdiffが見たいならgit show -mまたはgit show --first-parentで親指定を明示しましょう。rebaseで履歴をリニア化しておくとこの問題に遭遇しなくなります。

git diff と git show を混同する

git diff A(引数1つ)は「AのツリーとHEADの作業ツリー比較」になり、意図した「Aの変更内容」は表示されません。単一コミットの変更を見るならgit show A、2コミット間を比較するならgit diff A B、と明確に使い分けてください。

reflog期限切れのコミットと比較しようとする

HEAD@{2.months.ago}のようなreflog指定は、reflog(既定90日)を超えると参照不能になります。「過去の特定時点に戻りたい」なら、重要ポイントでタグを打っておくとずっと比較できる状態を保てます。タグ運用はタグ(tag)の使い方を参照。

よくある質問

Qgit show と git diff、単一コミットを見るならどっち?
Agit showが便利です。コミットメッセージ・作者・日時も一緒に表示され、親コミットとの差分を自動的に取ってくれます。git diff HEAD~1 HEADと等価ですが、入力がシンプルで読みやすくなります。
Q2コミット間のコミット一覧と差分を両方見たい
Agit log --oneline v1.2.0..v1.3.0で一覧、git log -p v1.2.0..v1.3.0で各コミットの差分付き一覧、git diff v1.2.0 v1.3.0で累計差分、と目的で使い分けます。
QHEAD~N と HEAD^N の違いは?
AHEAD~Nは「N個前の祖先」、HEAD^Nは「N番目の親」を指します。マージコミットの親を選ぶときだけ^Nが必要で、通常の一本線の履歴ならHEAD~Nが直感的です。
Q特定のコミットで変わったファイルの一覧だけ見たい
Agit show --name-only <SHA>またはgit diff-tree --no-commit-id --name-only -r <SHA>で取れます。変更種別(A/M/D)も欲しいなら--name-statusを使いましょう。
Qタグ同士でリリースノートを自動生成したい
Agit log --oneline v1.2.0..v1.3.0でコミット一覧、git shortlog v1.2.0..v1.3.0で著者別集計、git diff --stat v1.2.0 v1.3.0で規模感がそれぞれ一発で出ます。これらを整形してリリースノート本文にするのが定番です。
Qパッチとして別環境に適用したい
Aコミット情報を保持したいならgit format-patchgit am、単純な差分だけを当てたいならgit diff > file.patchgit apply file.patchです。
Qマージコミットの差分が変な表示になる
Aマージは親が複数あるため、デフォルトは「combined diff」という特殊形式で表示されます。通常のdiff形式が見たいならgit show -mまたはgit show --first-parent、特定親との比較ならgit diff <merge_SHA>^1 <merge_SHA>のように書きます。

関連記事

まとめ

  • コミット参照はSHA・HEAD・HEAD~N・HEAD^・タグ・ブランチ・reflog・@{u}の8種類
  • 2コミット間の内容比較はgit diff A B、単一コミット確認はgit show
  • 順序は「古い→新しい」で書くと差分が読みやすい
  • コミット一覧はgit log A..B、統計は--statshortlog
  • パッチ化は履歴保持ならformat-patch、単純差分ならgit diff > file.patch
  • マージコミットは^1^2で親を明示すると混乱しない
  • bisectやpickaxe(-S)と組み合わせると調査効率が上がる

コミット間の差分比較は、Gitの調査・レビュー・リリース管理すべての土台です。参照記法のバリエーションを覚え、git showgit diffを目的で使い分け、format-patchshortlogなどの補助コマンドと組み合わせれば、過去のどの時点とも素早く意味のある比較ができるようになります。タグ運用やbisectと合わせて、「いつ何が変わったか」を正確に追える履歴管理を目指しましょう。