結論

git diff とは、2つの状態(作業ツリー・ステージ・コミット・ブランチ)の違いを行単位で表示するコマンドです。表示するだけで、ファイルも履歴も変えません。

この記事でわかること

  • 比較対象別13パターンと目的別13オプションの早見表
  • A..B と A...B の違い、@@ 行の読み方
  • 何も出ないときのチェック11項目とエラー文12件の直し方

2026年10月16日更新|Git 2.43.0・Ubuntu 24.04 で実行確認

git diff は、作業ツリー・ステージ・HEAD・他のコミットのうち、どの2か所を比べるかでコマンドが変わります。

flowchart TD
    W["作業ツリー<br>編集中のファイル"]
    S["ステージ<br>git add した内容"]
    H["HEAD<br>最新コミット"]
    C["他のコミット・ブランチ"]
    W <-- "git diff" --> S
    S <-- "git diff --staged" --> H
    W <-- "git diff HEAD" --> H
    H <-- "git diff HEAD main" --> C
    W <-- "git diff main" --> C

何も付けない git diff は「まだ git add していない変更」、git diff --staged は「次のコミットに入る変更」、git diff A B は「A から B への変化」を表示します。

比較対象別の早見表

自分の状況の行を見ると、1行のコマンドと「何と何を比べているか」が分かります。

やりたいこと コマンド 比べるもの
add していない変更を見る git diff 作業ツリー ↔ ステージ
次のコミットに入る変更を見る git diff --staged ステージ ↔ HEAD(--cached も同じ)
手元の変更をまとめて見る git diff HEAD 作業ツリー ↔ HEAD
直前のコミットで変わった内容 git show HEAD(git diff HEAD~1 HEAD) 1つ前のコミット ↔ HEAD
特定のコミット1件の内容 git diff <ID>^ <ID>(git show <ID>) そのコミットの親 ↔ そのコミット
2つのコミット git diff <A> <B> A ↔ B(A から B への変化)
2つのブランチの先端どうし git diff main feature(main..feature) main の先端 ↔ feature の先端
ブランチで加えた変更だけ git diff main...feature 分岐点 ↔ feature の先端
リモートに無く手元にある変更 git fetch → git diff origin/main...main 分岐点 ↔ 手元の main
手元に無くリモートにある変更 git fetch → git diff main...origin/main 分岐点 ↔ origin/main
特定のファイル・フォルダだけ git diff -- app.py src/ -- の後ろがパス
特定の拡張子だけ git diff -- '*.py' 引用符で囲んだパターン
Git 管理外の2ファイル git diff --no-index a.txt b.txt ファイルシステム上の2つのパス

目的別のオプション早見表

やりたいこと オプション 出力の例
ファイル名だけ --name-only app.py
種別つきでファイル名 --name-status M app.py
ファイルごとの行数とグラフ --stat app.py | 2 +-
合計だけ1行で --shortstat 5 files changed, 5 insertions(+), 4 deletions(-)
追加・変更・削除で絞る --diff-filter=AM 追加(A)と変更(M)だけ
単語単位で見る --word-diff [-note,45-]{+note,40+}
空白の違いを無視 -w インデント変更を隠す
改行コードの違いを無視 --ignore-cr-at-eol CRLF 化した行を隠す
前後の行数を変える -U0 変更行だけ(既定は3行)
行末の空白・衝突マーカーを点検 --check app.py:2: trailing whitespace.
差分があれば終了コード1 --exit-code / --quiet スクリプトの条件分岐
逆向きに表示 -R + と - が入れ替わる
ファイルに保存 --output=x.patch 画面には出ない

確認環境:Git 2.43.0(Ubuntu 24.04)。使い捨てのリポジトリと、ローカルに作った bare リポジトリ(リモートの代わり)でこの記事の git コマンドを実行し、出力を英語表示(LANG=C)のまま載せています。コミットIDは実行のたびに変わります。オプションの仕様と difftool の設定の書式は Git 公式マニュアル(git-scm.com、最新版 2.56 系)、code --diff と VS Code の操作は VS Code 公式ドキュメント、IntelliJ IDEA の操作は JetBrains 公式ヘルプで確かめました(確認日 2026年10月16日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「git diffの使い方|早見表・オプション一覧・ブランチ間・ファイル名だけ」

git diffとは:何と何を比べているか

git diff を使いこなすコツは、どのコマンドがどの2か所を比べているかを押さえることです。Git には、ファイルの状態を持つ場所が3つあります。

場所 中身 更新するコマンド
作業ツリー いま編集しているファイルそのもの エディタでの保存
ステージ(インデックス) 次のコミットに入れる予定の内容 git add
HEAD 今のブランチの最新コミット git commit
  • コミットを書かない git diff は、作業ツリーとステージの比較です。git add した変更はここに出ません。
  • コミットを1つ書く git diff HEAD や git diff main は、そのコミットと作業ツリーの比較です。
  • コミットを2つ書く git diff A B は、A と B の比較です。作業ツリーは関係しません。

git add したのに git diff に何も出ないのは、作業ツリーとステージが同じ内容になったからです。その変更は git diff --staged のほうに移っています。

サンプルリポジトリを作る(コピペ用)

以降の実行結果は、次のリポジトリで取りました。そのまま貼り付けると同じ状態を作れます。

git --version   # git version 2.43.0

git init -b main shop && cd shop
git config user.name dev && git config user.email dev@example.com

cat > app.py <<'EOF'
def total(items):
    result = 0
    for item in items:
        result += item["price"]
    return result


def label(name):
    return "item: " + name
EOF

cat > util.py <<'EOF'
def to_int(value):
    return int(value)


def to_str(value):
    return str(value)


def is_empty(value):
    return value is None or value == ""
EOF

printf '# shop\n\n在庫を管理する小さなサンプルです。\n' > README.md
printf 'name,count\npen,120\nnote,45\n' > stock.csv
echo "old memo" > memo.txt
git add . && git commit -m "A: 最初のコミット"

# feature/tax ブランチで2コミット
git switch -c feature/tax
sed -i 's/result += item\["price"\]/result += item["price"] * item["count"]/' app.py
git commit -am "F1: 個数を掛ける"
printf '\n\ndef with_tax(amount, rate=0.1):\n    return int(amount * (1 + rate))\n' >> app.py
echo "tax notes" > tax.md
git add . && git commit -m "F2: with_tax を追加"

# main に戻って1コミット
git switch main
sed -i 's/サンプルです。/サンプルです。使い方は docs を参照。/' README.md
git commit -am "B: README を更新"

# ここから未コミットの変更を作る
sed -i 's/return "item: " + name/return "商品: " + name/' app.py   # add しない
printf 'name,count\npen,120\nnote,40\nclip,300\n' > stock.csv
git add stock.csv                                                    # add する
git mv util.py helpers.py
sed -i 's/def to_str/def to_text/' helpers.py && git add helpers.py  # リネーム+少し変更
git rm -q memo.txt                                                   # 削除
echo "new" > CHANGELOG.md && git add CHANGELOG.md                    # 新規追加
echo scratch > scratch.txt                                           # 未追跡のまま

この時点の状態です。

$ git status -sb
## main
A  CHANGELOG.md
 M app.py
R  util.py -> helpers.py
D  memo.txt
M  stock.csv
?? scratch.txt

左の列がステージ、右の列が作業ツリーの状態です。app.py だけが「まだ add していない変更」で、ほかはステージ済みです。記号の読み方は関連記事「git statusの見方|Untracked等の意味と-s短縮表示の記号一覧」で扱っています。

比較対象別の使い方と実行結果

git diff:add していない変更

$ git diff
diff --git a/app.py b/app.py
index 6d6c17c..156ebcb 100644
--- a/app.py
+++ b/app.py
@@ -6,4 +6,4 @@ def total(items):


 def label(name):
-    return "item: " + name
+    return "商品: " + name

ステージ済みの4ファイルと、未追跡の scratch.txt は出ません。git diff は「追跡しているファイルのうち、まだ add していない変更」だけを表示します。

git diff --staged:次のコミットに入る変更

$ git diff --staged
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..3e75765
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1 @@
+new
diff --git a/util.py b/helpers.py
similarity index 86%
rename from util.py
rename to helpers.py
index 01a0bdd..73337ff 100644
--- a/util.py
+++ b/helpers.py
@@ -2,7 +2,7 @@ def to_int(value):
     return int(value)


-def to_str(value):
+def to_text(value):
     return str(value)


diff --git a/memo.txt b/memo.txt
deleted file mode 100644
index be416ff..0000000
--- a/memo.txt
+++ /dev/null
@@ -1 +0,0 @@
-old memo
diff --git a/stock.csv b/stock.csv
index 459787c..65187df 100644
--- a/stock.csv
+++ b/stock.csv
@@ -1,3 +1,4 @@
 name,count
 pen,120
-note,45
+note,40
+clip,300

新規追加は new file mode と --- /dev/null、削除は deleted file mode と +++ /dev/null、リネームは rename from / rename to と表示されます。コミットの直前に git diff --staged を見ると、意図しない変更に気づけます。

--staged と --cached は同じ意味です。公式マニュアルでは --staged は --cached の別名と説明されています。

$ git diff --cached --name-only
CHANGELOG.md
helpers.py
memo.txt
stock.csv

コミットを添えると「ステージと、そのコミット」の比較になります。git diff --staged HEAD~1 は、ステージの内容を1つ前のコミットと比べます。

git diff HEAD:add した分もしていない分もまとめて

$ git diff HEAD --stat
 CHANGELOG.md          | 1 +
 app.py                | 2 +-
 util.py => helpers.py | 2 +-
 memo.txt              | 1 -
 stock.csv             | 3 ++-
 5 files changed, 5 insertions(+), 4 deletions(-)

app.py(未ステージ)も含めた5ファイルが出ました。「最新コミットから、手元で何を変えたか」を一度に見たいときに使います。

git diff A B:コミットどうし

ここからは、未コミットの変更を「C: 在庫更新とリネーム」としてコミットした状態で進めます(scratch.txt は削除しました)。

$ git log --oneline --graph --all
* 845f6b8 C: 在庫更新とリネーム
* cc1083e B: README を更新
| * bac422c F2: with_tax を追加
| * 0e68ee7 F1: 個数を掛ける
|/  
* 41a1d1e A: 最初のコミット

$ git diff HEAD~1 HEAD --stat
 CHANGELOG.md          | 1 +
 app.py                | 2 +-
 util.py => helpers.py | 2 +-
 memo.txt              | 1 -
 stock.csv             | 3 ++-
 5 files changed, 5 insertions(+), 4 deletions(-)

$ git diff HEAD~2 HEAD --name-status
A   CHANGELOG.md
M   README.md
M   app.py
R086    util.py helpers.py
D   memo.txt
M   stock.csv

git diff A B は「A から B への変化」です。 順番を逆にすると + と - が入れ替わります。コミットは、ID(845f6b8)、HEAD~1(1つ前)、タグ名、ブランチ名のどれでも指定できます。git diff A..B は git diff A B と同じ意味です。

git diff A..B と A...B:ブランチ間で結果が変わる

ブランチ間の比較には書き方が2つあり、結果が変わります。同じリポジトリで比べました。

$ git diff main..feature/tax --name-status     # 二点ドット(main feature/tax と同じ)
D   CHANGELOG.md
M   README.md
M   app.py
A   memo.txt
M   stock.csv
A   tax.md
R086    helpers.py  util.py

$ git diff main...feature/tax --name-status    # 三点ドット
M   app.py
A   tax.md

行数で比べると、違いがさらにはっきりします。

$ git diff main feature/tax --stat
 CHANGELOG.md          | 1 -
 README.md             | 2 +-
 app.py                | 8 ++++++--
 memo.txt              | 1 +
 stock.csv             | 3 +--
 tax.md                | 1 +
 helpers.py => util.py | 2 +-
 7 files changed, 11 insertions(+), 7 deletions(-)

$ git diff main...feature/tax --stat
 app.py | 6 +++++-
 tax.md | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

feature/tax で実際に変更したのは app.py と tax.md の2ファイルだけです。二点ドットで7ファイルも出るのは、main で進んだ変更(B・C)が「逆向きの差分」として混ざるからです。CHANGELOG.md が「削除」、memo.txt が「追加」と出ていますが、feature ブランチでそうした操作はしていません。

flowchart LR
    A["A 分岐点"] --> B["B"] --> C["C(main の先端)"]
    A --> F1["F1"] --> F2["F2(feature/tax の先端)"]
    C <-. "git diff main..feature/tax<br>先端どうし:7ファイル" .-> F2
    A <-. "git diff main...feature/tax<br>分岐点から:2ファイル" .-> F2
書き方 比べるもの 向いている場面
git diff main feature/tax main の先端 ↔ feature の先端 2つのブランチの「いまの中身」の違い
git diff main..feature/tax 上と同じ 上と同じ(書き方が違うだけ)
git diff main...feature/tax 分岐点(共通の祖先)↔ feature の先端 feature で加えた変更だけ。レビュー・マージ前の確認
git diff --merge-base main feature/tax 三点ドットと同じ 分岐点を使うことを明示したい(Git 2.30 以降)

三点ドットは、公式マニュアルで git diff $(git merge-base A B) B と同じと説明されています。サンプルでも確かめました。

$ git merge-base main feature/tax
41a1d1e3779b43aba1ab57f4c38a0c9bcbb8a4b7

$ git diff --merge-base main feature/tax --shortstat
 2 files changed, 6 insertions(+), 1 deletion(-)

分岐点はコミット A(41a1d1e)で、三点ドットと同じ行数になりました。プルリクエストの「Files changed」に近いのは三点ドットです。

git log でも .. と ... を使いますが、意味が git diff とは異なります。git log main..feature/tax は「feature にだけあるコミット」(F1・F2)、git log main...feature/tax は「どちらか片方にだけあるコミット」(B・C・F1・F2)です。

ファイル・フォルダ・拡張子を指定する(-- の意味)

$ git diff --staged -- stock.csv
diff --git a/stock.csv b/stock.csv
index 459787c..65187df 100644
--- a/stock.csv
+++ b/stock.csv
@@ -1,3 +1,4 @@
 name,count
 pen,120
-note,45
+note,40
+clip,300

-- は「ここから後ろはパス」という区切りです。 無くても動きますが、ブランチ名と同じ名前のファイルがあると Git が迷ってエラーになります。main というファイルを作って試しました。

$ touch main
$ git diff main
fatal: ambiguous argument 'main': both revision and filename
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

$ git diff --stat main --      # main をブランチとして扱う
 CHANGELOG.md          | 1 +
 ...
$ git diff -- main             # main をファイルとして扱う(差分なし)

パスの書き方は次のとおりです。

指定 意味
-- app.py src/ ファイルとフォルダ(複数可)
-- '*.py' 拡張子で絞る。引用符で囲み、シェルの展開を防ぐ
-- ':(glob)**/*.csv' サブフォルダも含めてパターンで絞る
-- . ':(exclude)*.md' *.md を除く(':!*.md' も同じ)
-- :/app.py リポジトリのルートからのパス
$ git diff main feature/tax --name-only -- '*.py'
app.py
util.py

$ git diff main feature/tax --name-only -- . ':(exclude)*.md'
app.py
memo.txt
stock.csv
util.py

パスは「いまいるフォルダ」からの相対指定です。 src/ の中で git diff -- app.py と打つと src/app.py を探すため、ルートの app.py の差分は出ません。ルートからのパスは :/app.py、親フォルダは ../app.py と書きます。

$ cd src
$ git diff --name-only -- app.py      # 何も出ない
$ git diff --name-only -- :/app.py
app.py

出力の読み方(@@ -1,5 +1,6 @@ の意味)

git diff の出力は、Linux の diff -u と同じ「unified 形式」に、Git 独自のヘッダーが付いたものです。5行の Dockerfile で、4行目を書き換え、1行足した例です。

$ git diff
diff --git a/Dockerfile b/Dockerfile
index 85d4f3a..9355dc2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,6 @@
 FROM python:3.12-slim
 WORKDIR /app
 COPY . .
-RUN pip install -r requirements.txt
+RUN pip install --no-cache-dir -r requirements.txt
+EXPOSE 8000
 CMD ["python", "app.py"]
行 意味
diff --git a/Dockerfile b/Dockerfile 比べているファイル。a/ が変更前、b/ が変更後
index 85d4f3a..9355dc2 100644 変更前後の内容の ID(blob のハッシュ)と、ファイルのモード
--- a/Dockerfile 変更前のファイル。新規追加なら /dev/null
+++ b/Dockerfile 変更後のファイル。削除なら /dev/null
@@ -1,5 +1,6 @@ ハンク(変更のかたまり)の見出し
先頭が空白の行 変わっていない行(前後の文脈。既定で3行ずつ)
先頭が - の行 変更前にだけある行(消えた行)
先頭が + の行 変更後にだけある行(増えた行)

@@ -1,5 +1,6 @@ は「変更前の1行目から5行分が、変更後の1行目から6行分になった」と読みます。 - 側が変更前、+ 側が変更後で、それぞれ「開始行,行数」です。この例では1行が - と + で置き換わり、1行が増えたので、5行が6行になりました。

  • 行数が省略された @@ -9 +9 @@ は1行という意味です。
  • @@ -9,0 +10,4 @@ は「変更前の9行目の後ろに、4行が追加された(変更前の行数は0)」という意味です。
  • @@ の右に def total(items): のような文字が付くことがあります。これはハンクの手前にある「英字で始まる行」を Git が添えたもので、関数名の目安です。先ほどの app.py の例では、変更は label 関数の中ですが、ハンクの手前にある英字始まりの行が def total(items): だったので、そちらが表示されました。

前後の行数は -U<行数> で変えられます。-U1 にするとハンクの開始位置が変わります。

$ git diff -U1
diff --git a/Dockerfile b/Dockerfile
index 85d4f3a..9355dc2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,3 +3,4 @@ WORKDIR /app
 COPY . .
-RUN pip install -r requirements.txt
+RUN pip install --no-cache-dir -r requirements.txt
+EXPOSE 8000
 CMD ["python", "app.py"]

\ No newline at end of file の意味

ファイルの末尾に改行が無いと、\ No newline at end of file という行が出ます。alpha\nbeta(末尾に改行なし)のファイルに、改行を足しただけの差分です。

$ git diff
diff --git a/note.txt b/note.txt
index 91896af..fbbee86 100644
--- a/note.txt
+++ b/note.txt
@@ -1,2 +1,2 @@
 alpha
-beta
\ No newline at end of file
+beta

-beta の直後の \ No newline at end of file は「この beta 行の末尾に改行が無かった」という印です。+beta の後ろには付いていないので、変更後は改行があります。中身は同じでも「改行の有無」が変わると、Git はその行を変更として数えます(--stat では 1 insertion(+), 1 deletion(-))。この差分は --ignore-space-at-eol、-b、-w のどれでも消えました。

最後の行に続けて行を足したときは、次のように「元の最終行が消えて、改行つきで増えた」という表示になります。

$ git diff
@@ -1,2 +1,3 @@
 alpha
-beta!
\ No newline at end of file
+beta!
+gamma

unified 形式そのものの読み方や patch コマンドは、関連記事「diffコマンドの使い方|-uの読み方・patch適用・オプション一覧」で扱っています。

ファイル名だけ・統計だけ・特定の拡張子だけ

ファイル名だけ(--name-only)

$ git diff --staged --name-only
CHANGELOG.md
helpers.py
memo.txt
stock.csv

変更されたファイルの一覧がほしいときの基本形です。 リネームは変更後の名前(helpers.py)で出ます。ブランチで加えた変更なら git diff --name-only main...feature/tax、特定のコミット1件なら git show --name-only --pretty="" <ID> です。

シェルスクリプトで受け取るなら、空白を含むファイル名にも対応できる -z(区切りを NUL 文字にする)と xargs -0 の組み合わせが確実です。

# 変更された .py だけを点検ツールに渡す例(削除されたファイルは除く)
git diff --name-only -z --diff-filter=AM main...feature/tax -- '*.py' | xargs -0 -r python3 -m py_compile

変更の種別つき(--name-status)

$ git diff --staged --name-status
A   CHANGELOG.md
R086    util.py helpers.py
D   memo.txt
M   stock.csv
文字 意味
A 追加(Added)
M 変更(Modified)
D 削除(Deleted)
R086 リネーム(Renamed)。数字は内容の一致度で、この例は86%
C コピー(Copied)。-C を付けたときに検出
T 種類の変更(通常ファイルとシンボリックリンクの入れ替わりなど)
U 未解決(マージのコンフリクト中)

種別で絞る(--diff-filter)

$ git diff --staged --diff-filter=A --name-only      # 追加だけ
CHANGELOG.md

$ git diff --staged --diff-filter=d --name-status    # 削除「以外」
A   CHANGELOG.md
R086    util.py helpers.py
M   stock.csv

$ git diff --staged --diff-filter=R --name-status    # リネームだけ
R086    util.py helpers.py

大文字は「その種別だけ」、小文字は「その種別を除く」という指定です。--diff-filter=AM のように複数の文字を並べられます。削除されたファイルを後続のコマンドに渡すと「ファイルがない」となるため、--diff-filter=d や --diff-filter=AM で除いておくと扱いやすくなります。マージのコンフリクト中に --diff-filter=U --name-only と書くと、未解決のファイルだけが出ます。

行数とグラフ(--stat / --shortstat / --numstat)

$ git diff --staged --stat
 CHANGELOG.md          | 1 +
 util.py => helpers.py | 2 +-
 memo.txt              | 1 -
 stock.csv             | 3 ++-
 4 files changed, 4 insertions(+), 3 deletions(-)

$ git diff --staged --shortstat
 4 files changed, 4 insertions(+), 3 deletions(-)

$ git diff --staged --numstat
1   0   CHANGELOG.md
1   1   util.py => helpers.py
0   1   memo.txt
2   1   stock.csv

$ git diff --staged --compact-summary
 CHANGELOG.md (new)    | 1 +
 util.py => helpers.py | 2 +-
 memo.txt (gone)       | 1 -
 stock.csv             | 3 ++-
 4 files changed, 4 insertions(+), 3 deletions(-)

$ git diff --staged --summary
 create mode 100644 CHANGELOG.md
 rename util.py => helpers.py (86%)
 delete mode 100644 memo.txt
オプション 向いている用途
--stat 人が見て、どのファイルがどのくらい変わったかをつかむ
--shortstat 合計だけを1行で。レビュー依頼の文面に添える
--numstat 「追加行数・削除行数・パス」のタブ区切り。スクリプトで集計する
--compact-summary --stat に新規(new)・削除(gone)の印を足す
--summary 新規作成・削除・リネームだけを一覧にする

--stat の幅は --stat=40 のように指定でき、--stat-count=2 で表示するファイル数を絞れます(残りは ... と表示されました)。

特定の拡張子だけ

パスの指定と組み合わせます。

$ git diff main feature/tax --name-only -- '*.py'
app.py
util.py

$ git diff main feature/tax --stat -- . ':(exclude)*.md'
 app.py                | 8 ++++++--
 memo.txt              | 1 +
 stock.csv             | 3 +--
 helpers.py => util.py | 2 +-
 4 files changed, 9 insertions(+), 5 deletions(-)

ブランチ間で比較する(マージ前・リモートとの差分)

マージ前に「何が入るか」を見る

マージ前の確認は三点ドットが基本です。git diff main...feature/tax で「feature で加えた変更だけ」が出ます(前述)。実際にマージした結果を確かめたいときは、--no-commit でコミット直前で止め、git diff --staged で見てから git merge --abort で戻せます。

$ git merge --no-commit --no-ff origin/main
Automatic merge went well; stopped before committing as requested

$ git diff --staged --stat
 stock.csv | 1 +
 1 file changed, 1 insertion(+)

$ git merge --abort

コンフリクトが起きると、git diff は「結合 diff」という特別な形になります。feature/tax を main にマージして試しました。

$ git merge feature/tax
Auto-merging app.py
CONFLICT (content): Merge conflict in app.py
Automatic merge failed; fix conflicts and then commit the result.

$ git diff --name-only --diff-filter=U
app.py

$ git diff
diff --cc app.py
index 156ebcb,84dd0a6..0000000
--- a/app.py
+++ b/app.py
@@@ -6,4 -6,8 +6,12 @@@ def total(items)


  def label(name):
++<<<<<<< HEAD
 +    return "商品: " + name
++=======
+     return "item: " + name
+ 
+ 
+ def with_tax(amount, rate=0.1):
+     return int(amount * (1 + rate))
++>>>>>>> feature/tax

diff --cc と @@@ が結合 diff の印で、各行の先頭に列が2つあります。左の列は「自分の側(HEAD)」、右の列は「相手の側(feature/tax)」と比べた結果で、+ はその側に無かった行、空白はその側にもあった行です。+ return "商品: " + name は自分の側にはあり相手の側には無い行、+ return "item: " + name はその逆、++ で始まる行はどちらにも無いコンフリクトのマーカーです。git diff --ours -- app.py で自分の側との差分、git diff --theirs -- app.py で相手の側との差分だけを見られます。マーカーの直し方は関連記事「Gitのコンフリクトの解消方法|マーカーの読み方から防ぎ方まで」で扱っています。

リモート(origin/main)との差分

リモートの状態は、git fetch で手元に取り込んだ origin/main(リモート追跡ブランチ)と比べます。fetch する前の origin/main は、最後に取得したときの状態です。

flowchart LR
    R["リモート origin の main"] -- "git fetch" --> O["origin/main<br>手元にある写し"]
    O <-- "git diff origin/main...main<br>手元だけの変更" --> L["main<br>手元のブランチ"]
    O <-- "git diff main...origin/main<br>リモートだけの変更" --> L

リモートに他の人のコミット D が push され、手元にはコミット E がある状態で確かめました。

$ git fetch
From ../origin
   845f6b8..ac51462  main       -> origin/main

$ git status -sb
## main...origin/main [ahead 1, behind 1]

$ git diff origin/main...main --stat      # 手元にだけある変更(push で送られる内容)
 README.md | 1 +
 1 file changed, 1 insertion(+)

$ git diff main...origin/main --stat      # リモートにだけある変更(pull で入る内容)
 stock.csv | 1 +
 1 file changed, 1 insertion(+)

$ git diff main origin/main --stat        # 先端どうし(両方が混ざる)
 README.md | 1 -
 stock.csv | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)
知りたいこと コマンド
push で送られる変更 git diff origin/main...main(git diff @{u}...HEAD も同じ)
pull で入ってくる変更 git diff main...origin/main
作業ツリーとリモートの違い git diff origin/main(未コミットの変更も含む)
コミット単位で見る git log --oneline --left-right main...origin/main

@{u}(@{upstream})は「今のブランチの上流ブランチ」を指す書き方で、origin/main を打たずに済みます。fetch と pull の違いは関連記事「git fetchとpullの違い|図解とpull --rebaseの使い分け」で扱っています。

特定のコミットの差分(git show・git diff A^ A)

コミット1件の内容を見る方法は3つあり、結果は同じです。

$ git show --stat HEAD
commit 845f6b8534f214d0f01549d55c1e41b9ce741a78
Author: dev <dev@example.com>
Date:   Fri Oct 16 17:41:08 2026 +0900

    C: 在庫更新とリネーム

 CHANGELOG.md          | 1 +
 app.py                | 2 +-
 util.py => helpers.py | 2 +-
 memo.txt              | 1 -
 stock.csv             | 3 ++-
 5 files changed, 5 insertions(+), 4 deletions(-)

$ git diff HEAD^ HEAD --stat     # 親と比べる
$ git diff HEAD^! --stat         # 同じ意味の短い書き方
書き方 意味
git show <ID> そのコミットのメッセージと差分。--stat や -- ファイル も使える
git diff <ID>^ <ID> 親コミットとの差分(メッセージは出ない)
git diff <ID>^! 上と同じ
git diff <ID>~1 <ID> 上と同じ(~1 と ^ はどちらも1番目の親)

^ は「1番目の親」、^2 は「2番目の親(マージで取り込んだ側)」、~2 は「1番目の親をたどった2世代前」です。マージコミットでは HEAD^2 と HEAD~2 が別のコミットを指します。

ファイル1つを、別のコミットの別の名前のファイルと比べることもできます。<コミット>:<パス> の形です。

$ git diff main:stock.csv feature/tax:stock.csv
diff --git a/stock.csv b/stock.csv
index 65187df..459787c 100644
--- a/stock.csv
+++ b/stock.csv
@@ -1,4 +1,3 @@
 name,count
 pen,120
-note,40
-clip,300
+note,45

「誰がいつ変えたか」まで追うときは git blame が向いています。git show と git blame の使い方は関連記事「git showとgit blameの使い方|誰がいつ変更したかを確認する」で扱っています。履歴をたどりながら差分を見る git log -p は、関連記事「git logオプション一覧|見やすくするformat指定子とalias設定例」で扱っています。

出力を見やすくするオプション

単語単位で表示する(--word-diff / --color-words)

行のごく一部だけを変えたときは、行単位より単語単位のほうが読みやすくなります。

$ git diff --word-diff
diff --git a/app.py b/app.py
index 6d6c17c..156ebcb 100644
--- a/app.py
+++ b/app.py
@@ -6,4 +6,4 @@ def total(items):


def label(name):
    return [-"item:-]{+"商品:+} " + name

$ git diff --word-diff --staged -- stock.csv
@@ -1,3 +1,4 @@
name,count
pen,120
[-note,45-]{+note,40+}
{+clip,300+}

[-...-] が消えた部分、{+...+} が増えた部分です。 単語の区切りは空白なので、note,45 のように空白のない文字列は丸ごと1語として扱われます。区切りを自分で決めたいときは --word-diff-regex を使います。.(任意の1文字)を指定すると1文字単位になります。

$ git diff --word-diff-regex=. -- app.py
    return "[-item-]{+商品+}: " + name

--color-words は --word-diff=color の短い書き方で、記号を付けずに色だけで区別します。端末向けで、ファイルに保存する用途には --word-diff(plain)が向いています。

オプション 表示
--word-diff [-消えた-]{+増えた+} の記号つき(plain)
--word-diff=color / --color-words 記号を付けず、色だけで区別
--word-diff=porcelain スクリプト向けの行形式
--word-diff-regex=<正規表現> 「1語」とみなすパターンを指定

前後の行数・関数全体(-U / -W)

$ git diff -U0 -- app.py
@@ -9 +9 @@ def label(name):
-    return "item: " + name
+    return "商品: " + name

-U0 で変更行だけになります。既定の3行は設定 diff.context で変えられます。-W(--function-context)は、変更を含む関数全体を文脈として表示します。

移動した行を色で区別する(--color-moved)

関数の順番を入れ替えただけの変更は、通常の表示では「削除+追加」に見えます。--color-moved を付けると、移動しただけの行が赤・緑ではない別の色(Git 2.43 の既定では太字のシアンとマゼンタ)で表示され、本当の変更と見分けられます。git config --global diff.colorMoved default で常時有効にできます。

そのほかの表示オプション

オプション 動き
--no-prefix a/ b/ を付けない(diff --git app.py app.py)
--diff-algorithm=patience 差分の取り方を変える(myers・minimal・patience・histogram)
--inter-hunk-context=<n> 近いハンクをつなげて表示
--stat-width=<n> --stat の幅
git --no-pager diff / git -P diff ページャー(less)を通さずに出す

改行コード・空白だけの差分の扱い(-w・autocrlf)

空白の違いを無視する(-w / -b / --ignore-space-at-eol)

インデントをそろえ直しただけの変更が混ざると、本当に見たい変更が埋もれます。app.py の2行目のインデントを深くし、行末に空白を3つ入れて試しました。

$ git diff -- app.py
@@ -1,9 +1,9 @@
 def total(items):
-    result = 0
+        result = 0   
     for item in items:
         result += item["price"]
     return result


 def label(name):
-    return "item: " + name
+    return "商品: " + name

$ git diff -w -- app.py
@@ -6,4 +6,4 @@ def total(items):


 def label(name):
-    return "item: " + name
+    return "商品: " + name

-w を付けると、空白だけが違う行は差分から外れ、中身の変更だけが残りました。 同じ状態で、無視する範囲の違いを --stat で比べました。

$ git diff --stat -- app.py                        # 2行の変更
 app.py | 4 ++--
$ git diff -b --stat -- app.py                     # インデント変更が消える
 app.py | 2 +-
$ git diff --ignore-space-at-eol --stat -- app.py  # 行末の空白だけ無視。インデント変更は残る
 app.py | 4 ++--
オプション 無視するもの
-w(--ignore-all-space) 空白の違いをすべて。空白の有無も無視
-b(--ignore-space-change) 空白の個数の違いと、行末の空白
--ignore-space-at-eol 行末の空白だけ
--ignore-cr-at-eol 行末の CR(改行コードの違い)だけ
--ignore-blank-lines 空行の追加・削除
-I <正規表現> その正規表現に全行が一致するハンク(Git 2.30 以降)

改行コード(CRLF)だけの差分

Windows のエディタで保存して改行コードが LF から CRLF に変わると、中身を変えていない行もすべて差分になります。 3行のファイルを CRLF に変え、2行目だけ中身を変えた例です(cat -A で CR を ^M として表示しています)。

$ git diff -- config.ini | cat -A
diff --git a/config.ini b/config.ini$
index 83db48f..34147ad 100644$
--- a/config.ini$
+++ b/config.ini$
@@ -1,3 +1,3 @@$
-line1$
-line2$
-line3$
+line1^M$
+line2 changed^M$
+line3^M$

$ git diff --stat -- config.ini
 config.ini | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

$ git diff --ignore-cr-at-eol -- config.ini
diff --git a/config.ini b/config.ini
index 83db48f..34147ad 100644
--- a/config.ini
+++ b/config.ini
@@ -1,3 +1,3 @@
 line1
-line2
+line2 changed
 line3

--ignore-cr-at-eol を付けると、中身を変えた2行目だけが残りました。-w でも同じ結果です。端末によっては CR が行末に ^M と表示されます。

core.autocrlf が true か input のときは、Git が比較の前に CRLF を LF に戻すため、改行コードだけの差分はそもそも出ません。 同じファイルで確かめました。

$ git -c core.autocrlf=input diff --stat -- config.ini
warning: in the working copy of 'config.ini', CRLF will be replaced by LF the next time Git touches it
 config.ini | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

改行コードは「表示で隠す」より「リポジトリとして統一する」ほうが根本の対処です。core.autocrlf と .gitattributes の text=auto の違いは、関連記事「Git改行コード設定|autocrlfと.gitattributesの違い」で扱っています。各ファイルの改行コードは git ls-files --eol で確認できます(i/lf w/crlf なら、リポジトリ内は LF、作業ツリーは CRLF)。

行末の空白・衝突マーカーを点検する(--check)

逆に、行末の空白のような「入れたくない空白」を探すときは --check が使えます。問題が見つかると終了コードが2になりました。

$ git diff --check -- app.py
app.py:2: trailing whitespace.
+        result = 0   
$ echo $?
2

--check は、マージのコンフリクトマーカー(<<<<<<<)の消し忘れと、ファイル末尾の空行も見つけます。

$ git diff --check
app.py:9: leftover conflict marker
app.py:11: leftover conflict marker
app.py:17: leftover conflict marker

$ git diff --check -- eof.txt
eof.txt:2: new blank line at EOF.

CRLF のファイルでは、行末の CR が trailing whitespace. として報告されます。CR を改行の一部として扱うには git -c core.whitespace=cr-at-eol diff --check とします(この指定で報告は消えました)。何を空白エラーとみなすかは設定 core.whitespace で決まり、公式ドキュメントでは blank-at-eol・space-before-tab・blank-at-eof が既定で有効です。コミット前に git diff --staged --check を実行する運用にすると、レビューで空白だけの指摘が減ります。公式マニュアルは --check と --exit-code を同時に使えないとしています。

バイナリファイル・巨大ファイルの差分

バイナリファイル

バイナリファイル(画像など)は行で比べられないため、Binary files ... differ とだけ表示されます。18バイトの PNG 風のファイルを21バイトに変えた例です。

$ git diff
diff --git a/logo.png b/logo.png
index 33bbbdf..25ba60c 100644
Binary files a/logo.png and b/logo.png differ

$ git diff --stat
 logo.png | Bin 18 -> 21 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

$ git diff --numstat
-   -   logo.png
やりたいこと 方法
サイズの変化だけ知る --stat(Bin 18 -> 21 bytes)
無理やりテキストとして見る --text(-a)。制御文字がそのまま出る
パッチにしてほかで当てる --binary(GIT binary patch 形式。git apply で適用できる)
テキストに変換して比べる .gitattributes に *.png diff=hex、設定 diff.hex.textconv に変換コマンド
テキストでもバイナリ扱いにする .gitattributes に *.min.js -diff(binary は -diff -merge -text をまとめた指定)

textconv の例です。変換コマンドに od -c を指定しました。

$ git config diff.hex.textconv "od -c"
$ echo '*.png diff=hex' > .gitattributes
$ git diff -- logo.png
diff --git a/logo.png b/logo.png
index 33bbbdf..25ba60c 100644
--- a/logo.png
+++ b/logo.png
@@ -1,3 +1,3 @@
 0000000 211   P   N   G  \r  \n 032  \n  \0  \0  \0  \r   I   H   D   R
-0000020  \0  \0
-0000022
+0000020  \0 001 002 003 004
+0000025

変換コマンドが無いと error: cannot run xxd: No such file or directory と fatal: unable to read files to diff で止まります。Excel や PDF も、変換コマンドを用意すれば同じ方法で比べられます。

巨大ファイル

20万行(約2MB)のログファイルで確かめました。1行だけ変えたときの git diff --stat は0.06秒で、ハンクも1つだけです。

$ git diff
@@ -99997,7 +99997,7 @@ row 99996
 row 99997
 row 99998
 row 99999
-row 100000
+row 100000 changed
 row 100001
 row 100002
 row 100003

全行を書き換えると、--stat のグラフは 400000 +++++... のように桁が大きくなるだけで、同じく0.07秒で終わりました。時間がかかるのは、差分そのものより「リネーム検出」です。ファイル数が多いと、次の警告とともに検出が省略されます。

warning: exhaustive rename detection was skipped due to too many files.
warning: you may want to set your diff.renameLimit variable to at least 2 and retry the command.

diff.renameLimit の既定値は公式ドキュメントでは1000です。警告が出て、リネームが「削除+追加」として表示されたときは、git -c diff.renameLimit=5000 diff ... のように上げて再実行します。

git diff と diff コマンドの違い(--no-index)

diff は Linux の汎用コマンドで、任意の2ファイルや2フォルダを比べます。git diff は Git の管理下にある状態どうしを比べるコマンドですが、--no-index を付けると、Git 管理外の2ファイルも比べられます。 同じ2つの設定ファイルで比べました。

$ diff -u dev.ini prod.ini
--- dev.ini 2026-10-16 17:40:55.361823149 +0900
+++ prod.ini    2026-10-16 17:40:55.361823149 +0900
@@ -1,3 +1,4 @@
-host=localhost
+host=db.example.com
 port=5432
 user=app
+pool=10

$ git diff --no-index dev.ini prod.ini
diff --git a/dev.ini b/prod.ini
index 96a7868..3c92c10 100644
--- a/dev.ini
+++ b/prod.ini
@@ -1,3 +1,4 @@
-host=localhost
+host=db.example.com
 port=5432
 user=app
+pool=10
項目 diff git diff --no-index
比べるもの 任意の2ファイル・2フォルダ 任意の2ファイル・2フォルダ
既定の形式 1c1 のような行番号形式(-u で unified) unified 形式(a/ b/ のヘッダーつき)
色・単語単位 版による --color・--word-diff・--stat がそのまま使える
終了コード 差分あり1・なし0 同じ(--no-index は --exit-code を含む)
Git が無い環境 使える 使えない
$ git diff --no-index --stat a b          # フォルダどうし
 {a => b}/x.ini       | 3 ++-
 /dev/null => b/y.ini | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

$ echo 'host=localhost' | git diff --no-index - dev.ini   # 標準入力とファイル
diff --git a/- b/dev.ini
index 0000000..96a7868 100644
--- a/-
+++ b/dev.ini
@@ -1 +1,3 @@
 host=localhost
+port=5432
+user=app

Git リポジトリの外で git diff a b と打つと、--no-index を付けなくても同じ動きになりました。リポジトリの外で引数を1つだけ渡すと warning: Not a git repository. Use --no-index to compare two paths outside a working tree と使い方が表示されます。diff コマンドのオプションは関連記事「diffコマンドの使い方|-uの読み方・patch適用・オプション一覧」で扱っています。

difftool・VS Code・IntelliJ での見方

git difftool

git difftool は、git diff と同じ比較対象を、指定した外部ツールで開くコマンドです。 引数の書き方は git diff と同じです。

$ git difftool --tool-help
'git difftool --tool=<tool>' may be set to one of the following:
        araxis           Use Araxis Merge (requires a graphical session)
        vimdiff          Use Vim

The following tools are valid, but not currently available:
        bc               Use Beyond Compare (requires a graphical session)
        ...

画面のない Linux で使えたのは上の2つでした。使えるツールは、インストールされているソフトによって変わります。-x で任意のコマンドを指定することもできます。確認のために diff -u を指定しました(-y は「開きますか?」の確認を省くオプションです)。

$ echo 'label v2' >> README.md
$ git difftool -y -x "diff -u --label before --label after" -- README.md
--- before
+++ after
@@ -2,3 +2,4 @@

 在庫を管理する小さなサンプルです。使い方は docs を参照。
 ## 使い方
+label v2

よく使う設定です。公式マニュアルでは、difftool.<tool>.cmd のコマンドに変更前のファイルが $LOCAL、変更後が $REMOTE として渡されると説明されています。

# VS Code で開く(code --wait --diff は VS Code 公式の CLI オプション)
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff "$LOCAL" "$REMOTE"'

# 毎回の確認を省く
git config --global difftool.prompt false
コマンド 動き
git difftool 未ステージの変更を1ファイルずつツールで開く
git difftool --staged ステージ済みの変更を開く
git difftool main...feature/tax ブランチで加えた変更を開く
git difftool -d main feature/tax フォルダ全体を一度に比較する(--dir-diff)
git difftool -t vimdiff その回だけツールを指定する

VS Code

VS Code 公式ドキュメントでの名前と、対応する git diff は次のとおりです。

見たいもの VS Code の操作 対応する git diff
add していない変更 ソース管理ビューの Changes でファイルを選ぶ git diff -- ファイル
次のコミットに入る変更 Staged Changes でファイルを選ぶ git diff --staged -- ファイル
特定のコミットの内容 Source Control Graph でコミットを選ぶ → ファイルを選ぶ(右クリック Open Changes で全ファイル) git show <ID>
ブランチ・タグとの比較 Source Control Graph でコミットを右クリック → Compare with... git diff <ID> <ブランチ>
上流ブランチとの比較 同じメニューの Compare with Remote git diff @{u} 相当
分岐点との比較 同じメニューの Compare with Merge Base git diff main...HEAD 相当
1ファイルの2つの版 Timeline ビューでコミットを右クリック → Select for Compare → 別のコミットで Compare with Selected git diff A B -- ファイル
任意の2ファイル ターミナルで code --diff a.txt b.txt git diff --no-index a.txt b.txt

差分エディターの表示は「More Actions(...)→ Diff View」で Inline・Side by Side・Automatic を切り替えられます。差分エディターのガターにある Stage ボタンで、選んだ行だけをステージすることもできます(git add -p に相当)。ドキュメントは、Compare 系の操作はコミット済みの内容を比べるだけで、チェックアウト中のブランチは切り替わらないと説明しています。

IntelliJ IDEA

JetBrains 公式ヘルプでの操作名です。

見たいもの IntelliJ IDEA の操作 対応する git diff
変更ファイルの差分 Commit ツールウィンドウでファイルをダブルクリック(Ctrl+D、または右クリック → Git | Show Diff) git diff -- ファイル
同じブランチの過去の版との比較 ファイルを右クリック → Git | Compare With Revision git diff <ID> -- ファイル
別のブランチ・タグとの比較 ファイルを右クリック → Git | Compare With Branch or Tag git diff <ブランチ> -- ファイル
任意の2ファイル Project ツールウィンドウで2ファイルを選び Ctrl+D(Compare Files) git diff --no-index a b
空白を無視 差分ビューアーの設定で Trim whitespaces / Ignore whitespaces / Ignore whitespaces and empty lines を選ぶ(既定は None) -w や --ignore-blank-lines に相当

エイリアス例(.gitconfig)

毎回オプションを打たずに済むように、よく使う形をエイリアスにしておくと便利です。次の設定を入れて、すべて動作を確かめました。

git config --global alias.d   'diff'
git config --global alias.ds  'diff --staged'
git config --global alias.dn  'diff --name-only'
git config --global alias.dst 'diff --stat'
git config --global alias.dw  'diff --word-diff'
git config --global alias.dh  'diff HEAD'
git config --global alias.db  'diff main...HEAD'
git config --global alias.dr  '!git diff "$(git rev-parse --abbrev-ref --symbolic-full-name @{u})...HEAD"'
エイリアス 使い方 意味
git ds --stat ステージ済みの変更の統計 git diff --staged --stat
git dn --staged ステージ済みのファイル名だけ git diff --name-only --staged
git db --stat 今のブランチで main から加えた変更 git diff main...HEAD --stat
git db --name-only -- '*.py' 同上を .py だけ パス指定もそのまま使える
git dr --stat 上流ブランチに無い手元の変更 git diff origin/main...HEAD --stat

! で始まるエイリアスはシェルのコマンドとして実行され、後ろに付けた引数がそのまま末尾に渡されます。dr は @{u} を git rev-parse でブランチ名に直してから三点ドットで比べています。エイリアスの書き方全般は関連記事「git aliasの設定方法とおすすめ一覧 .gitconfigコピペ用」で扱っています。

パッチにする・戻す(-R / --output)

git diff の出力をファイルに保存すると、そのままパッチ(変更内容を持ち運べるファイル)になります。

$ git diff > ../stock.patch         # 作業ツリーの変更をパッチにする
$ git restore stock.csv             # 変更をいったん戻す

$ git apply --stat ../stock.patch   # 何が変わるかを見る
 stock.csv |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
$ git apply --check ../stock.patch  # 適用できるか点検(出力なし=適用できる)
$ git apply ../stock.patch          # 適用
$ git apply -R ../stock.patch       # 逆向きに適用(取り消し)

同じパッチを2回当てようとすると、次のエラーになります。

error: patch failed: stock.csv:1
error: stock.csv: patch does not apply
コマンド 動き
git diff > x.patch / git diff --output=x.patch 未ステージの変更をパッチにする
git diff --staged > x.patch ステージ済みの変更をパッチにする
git diff main...feature > x.patch ブランチで加えた変更をパッチにする
git diff -R 逆向きの差分を表示(a/ と b/ が入れ替わる)
git apply --check x.patch 適用できるか点検(適用はしない)
git apply -R x.patch 逆向きに適用(取り消し)
git apply --3way x.patch そのまま当たらないときにマージ方式で適用

やってはいけない操作と、やり直す方法

git diff 自体はファイルを変えませんが、周りの操作で変更を失うことがあります。

操作 起きること やり直す方法
git diff --output=app.py / git diff > app.py のように既存のファイルに保存 そのファイルの中身が差分で上書きされる(確かめました) 追跡済みなら git restore app.py。未追跡なら戻せない
差分を見た後に git restore . / git checkout . 未コミットの変更がすべて消える 戻せない。先に git stash か git diff > x.patch
未ステージと未追跡を混同して git clean -f 未追跡のファイルが消える 戻せない。先に git clean -n で確認
パッチを2回 git apply patch does not apply で止まる(二重適用はされない) 当たっているかは git apply -R --check で確認
-w を付けたまま空白の変更をレビュー インデント崩れを見落とす 最後に git diff --check と、-w 無しで確認

実際に git diff --output=CHANGELOG.md HEAD~1 HEAD -- Dockerfile を実行すると、CHANGELOG.md の中身が差分で置き換わり、git status -s に M CHANGELOG.md と出ました。git restore CHANGELOG.md で元に戻りました。退避のしかたは関連記事「git stashの使い方|全コマンド実行結果つきで退避と復元を解説」で扱っています。

git diff が何も出ないときのチェック表

状況 確かめ方 見るコマンド
変更を git add 済み git status -s の左の列に M git diff --staged
新しく作ったファイル(未追跡) git status -s に ?? git add -N ファイル の後に git diff。または git status
すでにコミット済み git status が nothing to commit git show か git diff HEAD~1 HEAD
別のブランチにいる git branch --show-current git switch で移る。または git diff ブランチ名 -- ファイル
サブフォルダでパスを指定した -- app.py が src/app.py を指す -- :/app.py と書く
.gitignore で無視されている git check-ignore -v ファイル 関連記事「.gitignoreが効かない原因と直し方|check-ignoreで切り分け」で扱っています。
assume-unchanged / skip-worktree が付いている git ls-files -v | grep '^[a-zS]' に出る git update-index --no-assume-unchanged ファイル
比べる2つが同じ(片方が祖先) git merge-base --is-ancestor A B; echo $? が0 git log A..B でコミットの有無を見る
改行コードだけの変更で autocrlf が有効 git ls-files --eol で i/lf w/crlf 仕様どおり差分は出ない。CRLF を見たいなら git -c core.autocrlf=false diff
-w や --quiet を付けている コマンドを見直す オプションを外す
ページャーの画面に切り替わっただけ 画面の最下行に (END) q で戻る。git --no-pager diff で通さず出す

assume-unchanged を付けたファイルは、中身を変えても git diff にも git status にも出ません(確かめました)。git ls-files -v で先頭が小文字の h か S になっているファイルが該当します。

エラー文と直し方

エラー文(原文) 原因 直し方
fatal: ambiguous argument 'main': both revision and filename ブランチ名と同じ名前のファイルがある git diff main --(ブランチ)か git diff -- main(ファイル)
fatal: ambiguous argument 'origin/develop': unknown revision or path not in the working tree. そのブランチ・コミット・ファイルが手元にない。打ち間違い git fetch。git branch -a で名前を確かめる。パスなら -- の後ろに書く
fatal: path 'nosuch.txt' does not exist in 'main' main:nosuch.txt の形で、そのコミットにファイルがない git ls-tree main でパスを確かめる
warning: Not a git repository. Use --no-index to compare two paths outside a working tree リポジトリの外で git diff を実行した git diff --no-index a b
usage: git diff --no-index [<options>] <path> <path> --no-index にパスが2つ無い 2つのパスを渡す
error: bad --word-diff argument: foo モード名の誤り color・plain・porcelain・none のどれか
error: unknown change class 'Z' in --diff-filter=Z --diff-filter の文字の誤り A C D M R T U X B とその小文字
warning: exhaustive rename detection was skipped due to too many files. ファイル数が diff.renameLimit を超えた git -c diff.renameLimit=5000 diff ...
error: cannot run xxd: No such file or directory → fatal: unable to read files to diff textconv のコマンドが無い コマンドを入れるか、設定を外す
warning: in the working copy of 'config.ini', CRLF will be replaced by LF the next time Git touches it core.autocrlf が有効で、作業ツリーに CRLF がある エラーではない。改行コードの方針を決める(関連記事参照)
Binary files a/logo.png and b/logo.png differ バイナリとして扱われた エラーではない。--text か textconv
error: patch failed: stock.csv:1 / error: stock.csv: patch does not apply パッチの前後の行が、いまのファイルと一致しない。二重適用 git apply --3way。元になったコミットに合わせる

オプション一覧

この記事で扱ったオプションを、用途ごとにまとめました。

比較対象を決める 意味
--staged / --cached ステージと HEAD(またはコミット)を比べる
<commit> そのコミットと作業ツリー
<A> <B> / <A>..<B> A から B への変化
<A>...<B> / --merge-base <A> <B> A と B の分岐点から B への変化
--no-index <path> <path> Git 管理外の2つのパス
-R 2つの入力を入れ替える(逆向き)
-- <path>... パス・フォルダ・パターンで絞る
--relative サブフォルダの外の変更を除き、相対パスで表示
出力の量と形式 意味
--stat / --shortstat / --numstat 行数の統計(グラフ/合計1行/タブ区切り)
--compact-summary / --summary 新規・削除・リネーム・モード変更の要約
--name-only / --name-status ファイル名だけ/種別つき
--diff-filter=<ACDMRTUXB> 種別で絞る(小文字は除外)
-z 区切りを NUL にする(--name-only などと併用)
--output=<file> ファイルに書き出す
--exit-code / --quiet 差分があれば終了コード1(--quiet は出力なし)
--check 行末の空白・衝突マーカー・末尾の空行を報告。終了コード2
-s(--no-patch) 差分本体を出さない
見やすくする 意味
-U<n> / -W 前後の行数(既定3)/関数全体を文脈にする
--word-diff[=plain|color|porcelain] 単語単位
--color-words[=<regex>] --word-diff=color と同じ。正規表現で区切りを指定
--word-diff-regex=<regex> 「1語」の定義
--color-moved 移動しただけの行を別の色で表示
--no-prefix a/ b/ を付けない
--diff-algorithm=<name> myers(既定)・minimal・patience・histogram
空白・改行・検出 意味
-w / -b 空白をすべて無視/空白の量と行末を無視
--ignore-space-at-eol / --ignore-cr-at-eol 行末の空白だけ/行末の CR だけ
--ignore-blank-lines / -I <regex> 空行だけの変更/正規表現に一致する行だけの変更
-M[<n>%] / --no-renames リネーム検出(既定50%)/検出しない
-C / --find-copies-harder コピー検出(同時に変更された元だけ/全ファイルを候補に)
-l<n> リネーム検出を試みる上限(diff.renameLimit、既定1000)
-S<string> / -G<regex> その文字列の出現数が変わった/差分の行が正規表現に一致するファイルだけ
--text(-a) / --binary バイナリをテキスト扱い/適用できるバイナリパッチ
--textconv / --no-textconv 変換フィルターを使う/使わない

リネーム検出の既定のしきい値は、公式ドキュメントで50%です。サンプルの util.py → helpers.py は一致度86%なので、-M90% や --no-renames を付けると「追加+削除」(A helpers.py と D util.py)に変わりました。コピー検出は、cp README.md docs_README.md を add した状態で -C では A docs_README.md、--find-copies-harder では C100 README.md docs_README.md と表示されました。公式マニュアルのとおり、-C は「同じ変更の中で元のファイルも変更された場合」だけコピーを探します。

よくある質問

Q. git diff とは何ですか? A. Git が持つ2つの状態(作業ツリー・ステージ・コミット・ブランチ)の違いを行単位で表示するコマンドです。何も付けなければ「まだ add していない変更」、--staged で「次のコミットに入る変更」、git diff A B で「A から B への変化」が出ます。表示するだけで、ファイルも履歴も変えません。

Q. git diff コマンドの基本的な使い方は? A. 編集したら git diff で変更を確かめ、git add したら git diff --staged で次のコミットの中身を確かめる、という流れが基本です。git diff HEAD で両方をまとめて見られます。冒頭の早見表に、状況別のコマンドをまとめています。

Q. git diff でブランチ間の差分を見るには? A. 「そのブランチで加えた変更だけ」なら三点ドット(git diff main...feature)、「2つのブランチのいまの中身の違い」なら git diff main feature(二点ドットと同じ)です。この記事のサンプルでは、三点ドットが2ファイル、二点ドットが7ファイルという結果になりました。リモートとの比較は git fetch の後に git diff origin/main...main です。

Q. git diff でファイル名のみ(ファイル名だけ)を表示するには? A. --name-only を付けます。未ステージなら git diff --name-only、ステージ済みなら git diff --staged --name-only、ブランチで加えた変更なら git diff --name-only main...feature です。追加・変更・削除の種別も知りたいときは --name-status、変更の統計だけなら --stat です。

Q. git diff --check は何をするオプションですか? A. 差分の中の「行末の空白」「衝突マーカーの消し忘れ」「ファイル末尾の空行」を app.py:2: trailing whitespace. のような形で報告し、見つかると終了コード2で終わります。コミット前のチェックやCIで使えます。

Q. git diff のオプションで最初に覚えるものは? A. この記事で動かした中で、使う場面が多いのは --staged(次のコミットに入る変更)、--name-only(ファイル名だけ)、--stat(行数の統計)、-w(空白を無視)、--word-diff(単語単位)、三点ドット(ブランチで加えた変更)の6つです。全体は「オプション一覧」の節にまとめています。

Q. diff コマンドと git diff は何が違いますか? A. diff は任意の2ファイルを比べる Linux のコマンド、git diff は Git が管理する状態どうし(作業ツリー・ステージ・コミット)を比べるコマンドです。git diff --no-index a b とすると、Git 管理外の2ファイルも unified 形式で比べられます。

Q. git diff --staged と git diff --cached は違うものですか? A. 同じです。どちらも「ステージ(インデックス)と最新コミット」を比べます。公式マニュアルでは --staged は --cached の別名です。

Q. git diff と git show はどう使い分けますか? A. git show <ID> は「そのコミット1つで変わった内容」をメッセージつきで表示します。git diff は任意の2つの状態を比べるコマンドで、未コミットの変更やブランチ間の比較に使います。コミット1件の内容だけなら git show、範囲や比較対象を自分で決めたいときは git diff です。

Q. git add した変更は git diff で見られないのですか? A. 何も付けない git diff には出ません。git diff --staged で見られます。add の取り消しや -p での部分的な add は、関連記事「git addの取り消し方|1ファイル・全部・commit後の早見表と復元」で扱っています。

まとめ

  • git diff は未ステージの変更、git diff --staged は次のコミットに入る変更、git diff HEAD はその両方
  • ブランチで加えた変更だけを見るなら三点ドット(git diff main...feature)。二点ドットは先端どうしの比較で、main 側の変更が逆向きに混ざる
  • リモートとの差分は git fetch の後に git diff origin/main...main(push で送られる内容)
  • ファイル名だけなら --name-only、種別つきは --name-status、行数は --stat、種別の絞り込みは --diff-filter
  • @@ -1,5 +1,6 @@ は「変更前の1行目から5行 → 変更後の1行目から6行」。\ No newline at end of file は末尾の改行なし
  • 空白だけの差分は -w、改行コードだけの差分は --ignore-cr-at-eol。根本は改行コードの統一
  • --check は行末の空白・衝突マーカー・末尾の空行を終了コード2で報告
  • Git 管理外の2ファイルは git diff --no-index a b
  • 何も出ないときは「add 済み?」「未追跡?」「コミット済み?」「別ブランチ?」「パスの基準フォルダ?」の順に確かめる

参考・出典

確認日はいずれも 2026年10月16日です。

  • Git 公式マニュアル git-diff:https://git-scm.com/docs/git-diff
  • Git 公式マニュアル git-difftool:https://git-scm.com/docs/git-difftool
  • Git 公式マニュアル git-show:https://git-scm.com/docs/git-show
  • Git 公式マニュアル gitrevisions(^・~・@{u}・<rev>:<path>):https://git-scm.com/docs/gitrevisions
  • Git 公式マニュアル diff 関連の設定(diff.renameLimit・diff.context・diff.colorMoved など):https://git-scm.com/docs/diff-config
  • Git 公式マニュアル git-config(core.whitespace・core.quotepath・core.autocrlf):https://git-scm.com/docs/git-config
  • Git 2.30.0 リリースノート(--merge-base・-I<regex>):https://www.kernel.org/pub/software/scm/git/docs/RelNotes/2.30.0.adoc
  • Git 2.16.0 リリースノート(行末の CR を無視する diff):https://www.kernel.org/pub/software/scm/git/docs/RelNotes/2.16.0.adoc
  • VS Code Docs「Staging, commits, and undo」(diff editor・Diff View):https://code.visualstudio.com/docs/sourcecontrol/staging-commits
  • VS Code Docs「View source control history」(Compare with...・Timeline):https://code.visualstudio.com/docs/sourcecontrol/history
  • VS Code Docs「Command Line Interface」(code --diff・--wait):https://code.visualstudio.com/docs/editor/command-line
  • IntelliJ IDEA ヘルプ「Compare file and folder versions using Diff viewer」:https://www.jetbrains.com/help/idea/comparing-file-versions.html
  • IntelliJ IDEA ヘルプ「Compare files, folders, and text sources」:https://www.jetbrains.com/help/idea/comparing-files-and-folders.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「git diffの使い方|早見表・オプション一覧・ブランチ間・ファイル名だけ」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?