git diffでファイル指定する方法|pathspec・glob・除外(:!)・マジック指定の完全ガイド

git diff でファイル指定する方法 Git

プロジェクト全体のdiffは情報量が多すぎてレビューしづらく、知りたいのは「今自分がいじった特定ファイルの差分だけ」というケースは日常茶飯事です。git diffファイルやパスを指定すれば、ノイズを除いた本当に見たい差分だけを表示できます。

この記事では、git diffでファイル指定する方法を体系的に解説します。単一ファイル・ディレクトリ・globパターン・除外指定といったパススペック(pathspec)の書き方、--区切りの意味、working/index/HEADなどどの状態と比較するかとの組み合わせ、そしてシェル展開の落とし穴まで、実務で迷わない形で網羅します。

この記事で学べること

  • ファイル指定の基本書式と--区切りの必要性
  • 単一/複数/ディレクトリ/globパターンの書き分け
  • 除外指定(:(exclude))と大文字小文字無視(:(icase)
  • リポジトリトップ相対指定(:/)やリテラル指定(:(literal)
  • working tree・index・HEAD・コミットなど比較対象との組み合わせ
  • ステータス別の表示オプション(--name-only--stat-w
  • シェル展開・ブランチ名衝突などよくある落とし穴の回避
スポンサーリンク

基本:git diff にファイル名を渡すだけ

もっとも単純な使い方は、git diffのあとにファイル名を渡すことです。引数を何も指定しない場合は「作業ツリー ↔ index」の比較、そこにファイル名を追加するとそのファイルの同じ比較に絞り込まれます。

ファイル指定の基本
# ひとつのファイル
git diff index.html

# 複数ファイル(スペース区切り)
git diff index.html style.css

# ディレクトリ配下すべて
git diff src/

# カレントディレクトリ全体(= 引数なしと同じ)
git diff .

# リポジトリのルート相対で指定(どのサブディレクトリにいても同じ結果)
git diff :/src/auth.py

ポイント:パス指定は現在いるディレクトリからの相対パスが基本です。サブディレクトリからでも:/path/from/repo/rootでリポジトリトップ相対の指定ができます。スクリプト化するなら$(git rev-parse --show-toplevel)で絶対パスを取るのも確実です。

「--」区切りの意味と必要性

Gitコマンドでは--(ハイフン2つ)でコマンド引数とパスを明確に分離できます。ブランチ名とファイル名が同名だとGitが迷ってエラーになるため、この区切りを入れるのが安全です。

— 区切りの使いどころ
# 通常:パスはそのまま書ける
git diff src/auth.py

# -- で明示的に「ここから先はパス」と宣言
git diff -- src/auth.py

# ブランチ名と同名ファイルがある場合は -- で区別(必須)
git diff main -- main    # main ブランチ vs main というファイル

# 複数コミット比較にパスを追加する書式
git diff v1.2.0 v1.3.0 -- src/auth.py

# ブランチ比較+パス指定
git diff main feature -- src/

— を付けるべき場面

  • パス名とブランチ名/タグ名が衝突している可能性がある
  • パスが-で始まる(オプションと誤解されるのを防ぐ)
  • スクリプトで動的にパスを組み立てる(意図を明示してバグを予防)
  • commit指定+パス指定の順序を明確にしたい

globパターンで複数ファイルを一括指定

拡張子や名前パターンでまとめて指定できます。ただしシェル(bash等)が先にワイルドカードを展開してしまうため、必ずダブルクォートで囲むことでGitに解釈させます。

globパターンの使い方
# 拡張子で絞る(必ず引用符で囲む)
git diff -- "*.js"
git diff -- "*.ts" "*.tsx"

# 任意ディレクトリ配下(再帰)
git diff -- "src/**/*.py"
# **(再帰)はリポジトリのgitattributesやsparse-checkout設定と相性に注意

# ディレクトリ直下のファイルだけ
git diff -- "src/*.py"

# 名前パターン
git diff -- "test_*.py"

# 複数パターンの組み合わせ
git diff -- "*.css" "*.scss" "*.less"

注意:クォートを付け忘れると、シェルが先にglob展開を行ってからGitに渡します。現在存在するファイルだけが対象になり、削除されたファイルや今はマッチしないパスが漏れることがあります。Gitに解釈させたいときは必ずダブルクォートで囲みましょう:git diff -- "*.log"

除外指定:特定ファイルをdiffから外す

src/配下のdiffを見たいがtests/は除きたい」「ロックファイルの巨大diffを除外したい」といった場面では、マジックパススペック:(exclude)が便利です。

除外パススペック
# src/ 配下を見るが、テストは除外
git diff -- "src/" ":(exclude)src/tests/"

# 短縮形 :! も使える
git diff -- "src/" ":!src/tests/"

# ロックファイルを除外(よくあるノイズ対策)
git diff -- . ":(exclude)package-lock.json" ":(exclude)yarn.lock"

# 複数拡張子の除外
git diff -- . ":!*.min.js" ":!*.map"

# カレント全体から特定ディレクトリ除外
git diff -- . ":(exclude)node_modules/" ":(exclude)dist/"

ポイント:除外指定は包含指定と組み合わせる必要があります。「全体-除外」の形で書くのが基本。git diff -- ":!tests/"単独だと「tests以外」ではなく「何も指定していない+除外」扱いで期待通りに動きません。. ":!tests/"のように「含める範囲」を明示しましょう。

マジックパススペック一覧

Gitには:(name)の形で指定する便利なマジックパススペックが複数あります。知っておくと検索の幅が広がります。

記法 意味 短縮
:(exclude)path 対象から除外 :!path
:(icase)path 大文字小文字を無視してマッチ
:(literal)path globメタ文字をそのままの文字として扱う
:(top)path リポジトリトップからの相対パス :/path
:(glob)path Gitの**パターンを有効にする
:(attr:ATTR) gitattributes属性でフィルタ
マジックパススペックの活用例
# 大文字小文字無視(READMEかreadmeか曖昧なとき)
git diff -- ":(icase)readme.md"

# * や ? などのメタ文字を含むファイル名をそのまま探す
git diff -- ":(literal)log-*.txt"   # 「log-*.txt」という名前のファイル

# リポジトリ全体から
git diff -- ":/"
git diff -- ":/docs/README.md"

# 複数の条件を組み合わせる(カンマ区切り)
git diff -- ":(icase,glob)**/*.MD"

比較対象との組み合わせパターン

ファイル指定はどの状態と比較するかと組み合わせて使います。同じパス指定でも、比較対象を変えると結果が変わります。

コマンド 比較対象
git diff src/ 作業ツリー ↔ index(未addの変更)
git diff --cached src/ index ↔ HEAD(add済みの変更)
git diff HEAD src/ 作業ツリー ↔ HEAD(未add+add済み合計)
git diff main feature -- src/ ブランチ先端同士
git diff main...feature -- src/ merge-base基準(PR相当)
git diff v1.2.0 v1.3.0 -- src/ タグ間のファイル変化

比較対象の詳細は用途別に以下を参照してください:addしたファイルの変更を確認(staged)、ブランチ間の差分を比較(2ドットと3ドット)、コミット間の差分を比較(SHA指定・git show)。

ファイル指定と組み合わせる表示オプション

ファイル指定+表示オプション
# 変更ファイル一覧
git diff --name-only -- src/

# ファイル名+変更種別
git diff --name-status -- src/

# 行数統計
git diff --stat -- "*.py"

# 空白無視
git diff -w -- src/auth.py

# 前後行コンテキストを増やす
git diff -U10 -- src/auth.py

# ワード単位で比較
git diff --word-diff -- README.md

# 色を強制
git diff --color -- src/

旧記事でよくある誤解の訂正

  • -Uは「コンテキスト行数」オプションで数値が必須(例:-U10
  • -w空白無視--ignore-all-space)であって「ビジュアル表示」ではない
  • -cマージコミット用のcombined diffであって「簡潔表示」ではない
  • 「簡潔な表示」が欲しいなら--stat--shortstatを使う

実践シナリオ

シナリオ① 巨大PRから自分の担当ファイルだけ見たい

特定領域だけレビュー
# 自分の担当ディレクトリだけの差分
git diff main...feature -- src/auth/

# 統計で規模を把握
git diff --stat main...feature -- src/auth/

# テストだけ除外してコード本体だけ見る
git diff main...feature -- "src/" ":!**/tests/**"

シナリオ② ロックファイルを除外してコード差分を確認

ノイズ除去
# package-lock.json などの自動生成ファイルを除外
git diff -- . \
  ":(exclude)package-lock.json" \
  ":(exclude)yarn.lock" \
  ":(exclude)pnpm-lock.yaml" \
  ":(exclude)poetry.lock"

# エイリアス登録して使い回し
git config --global alias.diff-src \
  '!git diff -- . ":(exclude)package-lock.json" ":(exclude)yarn.lock"'
git diff-src

シナリオ③ 特定拡張子だけを一括チェック

TypeScriptだけ確認
# TypeScriptソースの変更だけ見る
git diff -- "*.ts" "*.tsx"

# ブランチ比較で
git diff main...feature -- "*.ts" "*.tsx"

# PRレビューで変更行数を言語別に把握
git diff --shortstat main...feature -- "*.ts"
git diff --shortstat main...feature -- "*.py"

シナリオ④ リポジトリ全体から特定パターンを探す

ConfigファイルとJSONだけ
# 設定ファイル系だけの変更
git diff main...feature -- ":/config/" ":/*.yml" ":/*.yaml" ":/*.json"

# CSSとSCSS
git diff main...feature -- "*.css" "*.scss"

# 大文字小文字無視でREADMEを全部
git diff main...feature -- ":(icase,glob)**/readme*"

GUI・IDEでのファイル単位比較

主要ツール

  • VS Code / Cursor:Source Controlパネルでファイルをクリックで個別diffビュー
  • JetBrains:Gitツールウィンドウで変更ファイル選択 → Compare with… / Show Diff
  • SourceTree:ファイル選択で下部にdiff、パスフィルタも指定可
  • GitHub Web:PR差分ページのFilter changed filesで絞り込み
  • git difftoolgit difftool -- src/auth.pyでGUIビューア起動

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

globを引用符なしで書いてシェル展開される

git diff -- *.logと引用符なしで書くと、シェルが先にファイル名リストに展開してからgitに渡します。現在存在するファイルだけが対象になり、削除されたファイルはマッチしません。「Gitに解釈させたい」ときは必ず引用符で囲む:git diff -- "*.log"。同様の問題はpathspec全般に起きます。

ブランチ名と同名ファイルで曖昧エラー

git diff mainのように書いたとき、mainというブランチとmainというファイル/ディレクトリが両方あるとambiguousエラーになります。曖昧になり得るときは--区切りで明示してください:git diff main --(ブランチ)/git diff -- main(ファイル)。

除外だけを書いて「含まれない」と勘違いする

git diff -- ":!tests/"と書くと、「tests以外を表示」ではなく「空(包含対象が無い)+除外」になり、期待と違う結果になります。除外は必ず包含対象と組み合わせるgit diff -- . ":!tests/"で「カレント全体からtests/を除く」になります。

-U を数値なしで使う

git diff -U file.pyと書くと「-Uの後の数値」がなく、予期しない挙動になります。必ず-U10のように数値を続けるか、-U0(文脈なし)、-U3(既定と同じ)のように明示しましょう。

サブディレクトリで相対パスがずれる

サブディレクトリでgit diff src/auth.pyと打つと、現在ディレクトリからの相対パスとして解釈されます。同じ指定でもディレクトリ位置で結果が変わるため、スクリプトや手順書ではリポジトリトップ相対の:/src/auth.pyや絶対パスを使うと事故が減ります。

よくある質問

Q— は必須?省略していいときは?
AGitが曖昧さなく判断できるなら省略可能です。ただし、ブランチ名とパスが同名、パスが-で始まる、スクリプトで動的に組み立てる、などのケースでは--を付けて明示するのが安全。迷うなら「常に--」で書くのが無難です。
Qglobの ** は使える?
A使えますが、引用符で囲む必要があります(git diff -- "src/**/*.py")。シェルによっては**を有効化しないと期待通りに動かないこともあり、Git側で確実に解釈させたい場合は:(glob)マジックを付けると確実です。
Qリポジトリのトップからのパスで指定したい
Aパスの先頭に:/を付けるか、:(top)pathマジックを使います。例:git diff -- :/src/auth.py。サブディレクトリからでもリポジトリトップ相対で指定できるので、手順書やスクリプトで便利です。
Q複数パターンの除外をまとめて指定したい
A:!patternを並べて書きます:git diff -- . ":!*.min.js" ":!dist/"。エイリアスでdiff-cleanのように登録しておくと毎回書かずに済みます。
Q大文字小文字を区別しない指定はできる?
A:(icase)マジックを使います:git diff -- ":(icase)readme.md"。Windowsからのリネーム整理などで役立ちます。globと組み合わせるなら":(icase,glob)**/readme*"のようにカンマ区切り。
Qファイル名に*?が入っているファイルを指定したい
A:(literal)マジックで解釈を無効化できます:git diff -- ":(literal)log-*.txt"は「log-*.txtという名前のファイル」を指します。通常運用ではほぼ出会いませんが、知っておくと便利です。
Q変更ファイルの一覧だけ欲しい
Agit diff --name-only -- src/でファイル名リスト、--name-statusで変更種別付き、--statで行数統計、と目的で使い分けます。パイプでxargsに渡して一括処理も可能です。

関連記事

まとめ

  • ファイル指定はgit diff [対象] -- <path>の形が基本
  • 単一/複数/ディレクトリ/globが可能——globは必ず引用符で囲む
  • 除外は:!pathまたは:(exclude)path包含と組み合わせる
  • リポジトリトップ相対なら:/pathまたは:(top)マジック
  • 大文字小文字無視::(icase)、リテラル::(literal)
  • 比較対象(working/index/HEAD/コミット/ブランチ)と自由に組み合わせ可能
  • ブランチ名との衝突を防ぐため、迷ったら--区切りを明示

ファイル指定を使いこなすと、巨大プロジェクトでも「自分が見たい差分だけ」を素早く取り出せます。パススペックの基本+マジック(:!:/:(icase))を押さえれば、レビュー・リリースノート作成・影響範囲調査がぐっと効率化します。ブランチ名衝突やシェル展開といった落とし穴さえ避ければ、日常のあらゆる場面で役立つ強力な武器になります。