- Git
git diffの使い方|早見表・オプション一覧・ブランチ間・ファイル名だけ
結論
git diff とは、2つの状態(作業ツリー・ステージ・コミット・ブランチ)の違いを行単位で表示するコマンドです。表示するだけで、ファイルも履歴も変えません。
この記事でわかること
- 比較対象別13パターンと目的別13オプションの早見表
A..BとA...Bの違い、@@行の読み方- 何も出ないときのチェック11項目とエラー文12件の直し方
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期連続の黒字決算。