【Git】ブランチ間の差分を比較する方法|2ドットと3ドットの違い・PR相当diffの完全ガイド

【Git】ブランチ間の差分を比較する方法 Git

「mainとfeatureブランチで何が違うのか知りたい」「PRを出す前に本線との差分を確認したい」「長く放置されたブランチをどうするか判断したい」——ブランチ間の差分比較は、レビューやマージ判断で欠かせない操作です。

この記事では、Gitでブランチ間の差分を比較する方法を体系的に解説します。最大のポイントはA..B」と「A...B」の違い。点の数を間違えると「PRのbase時点からの変更だけ見たかったのに、mainの新しい変更まで逆差分で混ざる」事故が起きます。ドット数の正しい使い分け、ファイル別・コミット別の比較、リモートブランチとの比較、GUIでの可視化まで、実務で役立つ形でまとめます。

この記事で学べること

  • ブランチ差分の2つの視点:ファイル内容の差分コミットリストの差分
  • git diff A BA..BA...Bの違いと使い分け
  • PR提出前に「自分のブランチがmainに対して加えた変更」だけを見る方法
  • ahead/behind件数の確認(git rev-list --count
  • リモートブランチとの比較(origin/main..HEAD
  • ファイル・パス・パターンでの絞り込み
  • GUI/IDEでの視覚的な比較方法
スポンサーリンク

まず整理:ブランチ差分には2つの視点がある

「ブランチの差分」と一口に言っても、見たいものは大きく2つに分かれます。

視点 目的 使うコマンド
ファイル内容の差分 「今、どのコードが違うか」を見る git diff
コミットリストの差分 「どんなコミットが違いを生んでいるか」を見る git log(範囲指定)

ポイント:レビューやPR準備ではコミット一覧内容差分両方見るのが正解です。コミット一覧で変更の粒度と履歴を、内容diffで実際のコード変更を確認——この2段階でチェックするとレビュー漏れが減ります。

最重要:「A..B」と「A...B」の違い

ブランチ比較で最大の落とし穴が、ドット数の違いです。git diffgit logでも意味が違うため、しっかり区別しましょう。

git log の場合

git log のドット違い
# A..B : B にいて A にいない コミット(= B固有のコミット)
git log main..feature
# → feature でしか行われていないコミット一覧

# A...B : A と B 双方に固有のコミット(対称差)
git log main...feature
# → main と feature のどちらかにしかないコミット全部

git diff の場合(少しややこしい)

git diff のドット違い
# A B と A..B は同じ意味
# 「A と B の先端同士の内容差分」(直接比較)
git diff main feature
git diff main..feature   # 同じ

# A...B は「merge-base と B の差分」
# つまり「feature が分岐点以降に加えた変更だけ」
git diff main...feature
記法 log(コミット) diff(内容)
A B(空白区切り) logでは使わない) AとBの先端の内容差(=A..B
A..B B固有のコミット AとBの先端の内容差
A...B A・B双方の固有コミット merge-baseとBの差(PRと同じ見え方)

PRプレビュー相当の差分を見たいときは?

「自分のbranchがmainに対して何を追加したか」——つまりGitHubのPR画面で表示されるのと同じ差分を見たいならgit diff main...feature...3ドット)を使います。main..feature(2ドット)だと、mainの新しい変更をマイナス方向で含んでしまうため、PRと見た目が一致しません。

基本コマンド:ブランチ間の内容を比較

よく使う基本形
# 先端同士の内容差分
git diff main feature

# 3ドットで「featureがmainから分岐して加えた変更」のみ(PR相当)
git diff main...feature

# 変更ファイル名だけ
git diff --name-only main...feature

# ファイル名+変更種別(A=追加/M=変更/D=削除/R=rename)
git diff --name-status main...feature

# 統計(行数変化)
git diff --stat main...feature

# ワード単位で差分表示(自然言語や文書向け)
git diff --word-diff main...feature

# 空白変更を無視して本質的な差分だけ
git diff -w main...feature

# 前後の文脈を10行に拡大(既定は3行)
git diff -U10 main...feature

ファイル・パスで絞り込む

特定のファイルやディレクトリだけの差分を見たいときは--区切りでパス指定します。

パス指定で絞り込み
# 特定ファイルの差分
git diff main feature -- src/auth.py
git diff main...feature -- src/auth.py

# ディレクトリ配下
git diff main...feature -- src/

# 複数パス
git diff main...feature -- src/auth.py tests/auth_test.py

# 拡張子で絞る(glob)
git diff main...feature -- "*.js" "*.ts"

# 除外(:(exclude) パススペック)
git diff main...feature -- . ":(exclude)tests/"

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

コミットリストで差分を見る(git log)

ファイル内容ではなく「どんなコミットがあるか」を比較したいときはgit logを使います。

コミットリストの比較
# feature にいて main にいないコミット(B固有)
git log --oneline main..feature

# 両方向(A・B双方の固有コミットを表示)
git log --oneline --left-right main...feature
# 出力例:
# < a1b2c3d mainにしかない修正
# > e4f5g6a featureでの追加
# < が左(main)、> が右(feature)側を意味

# グラフ付きで分岐を可視化
git log --oneline --graph --left-right main...feature

# author別に集計
git shortlog main..feature

# マージコミットを除外してfeatureの純粋な変更だけ
git log --oneline --no-merges main..feature

コミット間の比較の詳しい使い方はコミット間の差分を比較する方法もあわせて参照してください。

ahead / behind の件数を素早く確認

「自分のブランチはmainに対して何コミット先/遅れているか」を知りたいときはgit rev-list --countが便利です。

ahead/behind件数を数える
# feature は main に対して何コミット先か
git rev-list --count main..feature
# → 5

# feature は main に対して何コミット遅れているか
git rev-list --count feature..main
# → 3

# 双方向を一発で(左:ahead / 右:behind)
git rev-list --left-right --count main...feature
# 出力例: "3    5"   ← main側3 / feature側5 のコミット

# 現在ブランチと upstream の関係を表示
git status -sb
# 出力例: ## feature...origin/feature [ahead 2, behind 1]

# branchの一覧と upstream 追跡情報
git branch -vv

ポイント:チーム開発で頻繁に使うのは「git rev-list --left-right --count」。「mainに対して3コミット先、2コミット遅れ」という状態が一発で分かるので、マージ前にrebaseや同期が必要か即判断できます。

リモートブランチとの比較

PR提出前にリモート本線との差分を見たり、他メンバーのブランチと自分を比較したり、というケースは頻出です。比較前にgit fetchで情報を最新化しておきましょう。

リモートとの差分
# 最新化(必須)
git fetch --all --prune

# 自分のブランチ vs リモートmain(PRを出す前の最終確認)
git diff origin/main...HEAD

# リモート同士の比較(他メンバーのブランチと)
git diff origin/main...origin/feature/review

# 特定のファイルだけ
git diff origin/main...HEAD -- src/auth.py

# PR対応コミットだけの一覧
git log --oneline origin/main..HEAD

# 自分のローカルとリモート追跡ブランチの差
git diff feature origin/feature

リモートブランチの確認方法全般はリモートブランチを確認する方法を参照してください。

merge-baseの概念と実務活用

A...Bの3ドット記法が参照する「分岐点」がmerge-baseです。「このブランチはどこから分かれたんだっけ?」を知ることで、rebaseやcherry-pickの起点を正確に決められます。

merge-base の確認
# mainとfeatureの共通祖先SHAを表示
git merge-base main feature
# → a1b2c3d   ← この時点から feature が分岐した

# merge-baseの内容を詳しく見る
git show $(git merge-base main feature)

# 3ドットは内部的には merge-base を使っている
git diff $(git merge-base main feature) feature
# ≒ git diff main...feature

# 複数のmerge-base候補(クロスマージされている場合)
git merge-base --all main feature

なぜ3ドットがPRと一致するか

PRのdiffはbase branch(mainなど)の分岐点以降の変更だけを表示します。mainの新しいコミット(分岐後にmain側だけ進んだ部分)は、PRの「変更内容」には含まれません。3ドットA...Bmerge-base(A,B)Bの差分を取るため、PRと同じ見え方になります。レビュー前の自己確認ではこちらを使いましょう。

実践シナリオ

シナリオ① PR提出前の最終確認

自分の作業を俯瞰する
# 最新化
git fetch origin

# 変更ファイルを俯瞰
git diff --stat origin/main...HEAD

# コミット数確認
git rev-list --count origin/main..HEAD

# コミット一覧を確認
git log --oneline origin/main..HEAD

# 内容を精読
git diff origin/main...HEAD

# 問題なければpush
git push origin -u feature/my-branch

シナリオ② 長命ブランチのズレを把握

放置ブランチの健康診断
# mainからどれだけズレたか
git rev-list --left-right --count origin/main...feature/legacy
# 出力例: "50    12"  ← main側50進行、feature側12固有

# 衝突しそうなファイルを探す
git diff --name-only origin/main...feature/legacy
git diff --name-only feature/legacy...origin/main
# 両方に出るファイルがコンフリクト候補

# マージ前の本線取り込み
git switch feature/legacy
git rebase origin/main

シナリオ③ 別ブランチから特定変更だけ持ち込む前の下見

cherry-pick候補を確認
# 別ブランチの固有コミット一覧
git log --oneline main..hotfix/urgent

# 1コミットだけ詳細を見る
git show <SHA>

# 取り込む
git switch main
git cherry-pick <SHA>

シナリオ④ マージ済みかどうかの判定

merge済み判定
# featureがmainに完全マージされているか(件数で判定)
git rev-list --count main..feature
# → 0 なら feature の全コミットが main に含まれている

# ブランチ一覧でマージ済みを絞る
git branch --merged main

# squash mergeされた場合の判定は内容で
git diff main...feature --stat
# 差分が空 or ごく少量なら取り込み済み

ブランチ削除や統合判断の詳細はブランチを削除する方法も参考にしてください。

GUI・IDEでの比較

主要ツールでのブランチ比較

  • VS Code / Cursor:Source Control → ブランチ選択 → 「Compare with」、GitLens拡張でCompare Branchesコマンド
  • JetBrains(IntelliJ/WebStorm):Gitツールウィンドウ → Log → ブランチ選択 → 右クリック「Compare with Current」
  • SourceTree:Branches右クリック → Compare with… → 対象ブランチ選択
  • GitHub Webhttps://github.com/user/repo/compare/main...feature(3ドットに注意)
  • gitk –all:コマンドライン寄りの視覚化
  • git difftool:任意のGUI差分ツールを呼び出し(設定必要)

GitHubのcompare URL

ブラウザで比較ページを開く
# GitHub UI で比較するURL形式
# https://github.com/{owner}/{repo}/compare/{base}...{compare}
open "https://github.com/user/repo/compare/main...feature"

# 三点記法:PRと同じ差分ビューで表示される
# このURLのDiff表示がgit diff main...featureと同等

ポイント:GitHubのcompare/A...BURLは3ドット固定です。「2ドットで表示したい」場合はCLI(git diff main feature)を使うしかありません。GitHub PRが3ドット差分なので、レビュー前の事前確認はCLIでも3ドットgit diff main...featureで揃えるのが自然です。

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

PRと差分が違う!と悩んで2ドットで見続ける

PRはmerge-baseを基準にした3ドット相当の差分を表示します。git diff main feature(2ドット相当)で比較すると、mainの新しいコミットがマイナス差分として現れ、PRと見た目が違います。レビュー前の自己確認や「PRに含まれる変更だけ見たい」ケースはgit diff main...feature(3ドット)を使いましょう。

git log A B と git log A..B を混同する

git log A B(空白区切り)は「A または B から到達できる全コミット」を表示する、A..Bは「B固有のコミット」を表示、と意味が全く違います。ブランチ間比較で使うのはほぼ常にA..BまたはA...Bなので、空白区切りは誤用になりがち。git logでは必ずドット記法を使う習慣を。

fetch せずにリモート比較する

git diff origin/main...HEADローカルに保存されているorigin/mainのスナップショットと比較します。最新のリモート状態を反映していないと、古い情報で差分を取ってしまいます。比較前には必ずgit fetch --all --pruneを実行しましょう。

空白だけの差分で「変更あり」と判断する

エディタ設定(インデント・改行コード)の違いで、意図しない空白変更がdiffに混ざることがあります。本質的な変更を見たいときは-w--ignore-space-at-eolを付けて空白を無視した比較をしましょう。EditorConfigやlinter整備で予防も可能です。

rename を認識させずに「削除+追加」として見る

ファイル名変更はデフォルトである程度検出されますが、大幅な内容変更を伴うとrename認識が外れて「旧ファイル削除+新ファイル追加」として表示されます。git diff -M(rename detection強化)や-M50%(閾値指定)で認識精度を上げられます。ブランチ比較で「削除が多い」と感じたら試してみてください。

よくある質問

Qgit diff A..B と git diff A…B、どっちを使えばいい?
A「PRと同じ差分」「ブランチが本線から分岐して加えた変更だけ」を見たいなら3ドットA...B、「今この瞬間のAとBの先端同士の差」を見たいなら2ドットA..Bまたは空白区切り。迷ったら3ドットがPR感覚に合うので初手で選びやすいです。
Qgit log A..B と git log A…B は?
AA..Bは「B固有のコミット」、A...Bは「A・B双方の固有コミット」(対称差)。PR相当が欲しいならA..B(B側だけ)、両ブランチのズレを両方向で見たいならA...Bです。
Q自分のブランチがmainから何コミット先行・遅れているか知りたい
Agit rev-list --left-right --count main...featureで一発です。「左の数字=main側の進行(behind)、右の数字=feature側の固有(ahead)」の形で表示されます。git status -sbでもupstreamとの関係なら見えます。
Q特定ファイルだけ差分を見たい
Agit diff main...feature -- path/to/fileのようにパスを追加します。ディレクトリや拡張子globも使えます。詳細はgit diff でファイル指定する方法を参照。
Qsquash mergeされたブランチのマージ済み判定がうまくいかない
Asquash/rebase mergeはSHAが変わるためgit branch --mergedでは未マージ扱いになります。内容ベースで判定するならgit diff main...feature --statで差分がほぼ空かを見るのが実用的です。
QGitHubのPRと同じ差分をCLIで見たい
Agit fetch origingit diff origin/main...HEADでGitHubのPR差分と同じビューが得られます。3ドット記法が重要です。
Q共通祖先(merge-base)が複数あって困る
Agit merge-base --all A Bで候補を全部表示できます。クロスマージを繰り返したリポジトリで起きる稀なケース。PRでdiffがおかしい場合、merge-baseの混乱が原因のことがあります。rebaseで履歴を整えるのが根本対処です。

関連記事

まとめ

  • ブランチ差分には「内容差分(diff)」と「コミット差分(log)」の2視点
  • ドット記法が最重要A BA..B(先端同士)、A...B(merge-base基準=PR相当)
  • PR確認はgit diff main...featuregit diff origin/main...HEAD
  • ahead/behindはgit rev-list --left-right --count A...B
  • ファイル絞り込みは--区切りでパス指定
  • リモート比較前は必ずgit fetch --all --pruneで最新化
  • squash/rebase mergeはSHAが変わるため、merged判定は差分内容で行う
  • GitHub WebのcompareURLやGUIも合わせて視覚的に確認

ブランチ間の差分比較は、PR提出前の最終確認や長命ブランチの健康診断、cherry-pick候補の見極めなど、日常的な判断の土台になります。特にドット数の違い(2ドット vs 3ドット)を理解しておくと、PR画面と同じ差分をCLIで再現でき、レビュー前の自己チェックが格段に正確になります。GUIツールも併用しながら、比較結果をもとにrebase・cherry-pick・マージ判断を的確に行っていきましょう。