- Git
git showとgit blameの使い方|誰がいつ変更したかを確認する
git show は「1つのコミットで何が変わったか」を表示するコマンド、git blame は「ファイルの各行を最後に変更したのは誰で、いつか」を表示するコマンドです。 この2つを組み合わせると、「この行はなぜこうなっているのか」を、blame でコミットを特定し、show でその中身と理由(コミットメッセージ)を読む、という流れで調べられます。
この記事では、6つのコミットを持つ小さなリポジトリを用意し、すべてのコマンドを Git 2.43.0 で実行した結果を載せています。目的別のオプション早見表、出力の各列の読み方、整形だけのコミットを飛ばす --ignore-revs-file、行の履歴をまとめて追う git log -L、文字列の出現を追う git log -S / -G までを一続きで扱い、最後に「blame → show → 親コミットへ再 blame」の調査手順をコピペできる形でまとめました。
git showとgit blameの早見表
やりたいこと別のコマンド
| やりたいこと | コマンド |
|---|---|
| 最新のコミットの内容を見る | git show |
| 指定したコミットの内容を見る | git show a8661df |
| 変更されたファイル名だけ見る | git show --name-only a8661df |
| 追加・変更・削除の種別つきで見る | git show --name-status a8661df |
| 変更の行数(統計)だけ見る | git show --stat a8661df |
| 特定のファイルの差分だけ見る | git show a8661df -- README.md |
| 差分を出さず、作成者と日時だけ見る | git show -s --format="%h %an %ad %s" a8661df |
| その時点のファイルの中身を見る | git show d8646ea:stock.py |
| 空白だけの変更を除いて見る | git show -w 7b09ed3 |
| 各行を誰がいつ変更したか見る | git blame stock.py |
| 行範囲を絞る | git blame -L 6,7 stock.py |
| 関数単位で絞る | git blame -L :is_low_stock stock.py |
| 空白だけの変更を無視する | git blame -w stock.py |
| 別ファイルからの移動を追う | git blame -C stock.py |
| 整形コミットを飛ばす | git blame --ignore-revs-file .git-blame-ignore-revs stock.py |
| 過去の時点で blame する | git blame adce066^ -- stock.py |
| ある行の履歴を全部見る | git log -L 7,7:stock.py |
| 文字列が増減したコミットを探す | git log -S "0.08" |
| 差分に文字列が出るコミットを探す | git log -G "count <" |
show と blame と log の使い分け
| コマンド | 起点 | わかること | 向いている問い |
|---|---|---|---|
git show |
コミット | そのコミットの作成者・日時・メッセージ・差分 | このコミットは何を変えたのか |
git blame |
ファイルの行 | 各行を最後に変更したコミット・作成者・日時 | この行は誰がいつ書いたのか |
git log -L |
行範囲・関数 | その範囲を変更したコミットを新しい順にすべて | この行はどう変わってきたのか |
git log -S / -G |
文字列 | その文字列を出し入れしたコミット | この記述はいつ入り、いつ消えたのか |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「git showとgit blameの使い方|誰がいつ変更したかを確認する」
検証に使ったリポジトリ
検証環境は Git 2.43.0(Linux)です。オプションの説明は、git-scm.com の git-blame のページ(開いた時点で 2.56.0 版)を今回開いて確認しました。
在庫を扱う小さな Python ファイルを題材に、3人が6回コミットした履歴を作りました。
git log --format='%h %an %ad %s' --date=short
ca57ae7 Tanaka Aoi 2026-09-10 format_itemをdisplay.pyへ移動
adce066 Sato Hana 2026-08-20 在庫少の判定を10個以下に修正
7b09ed3 Suzuki Ken 2026-07-01 フォーマッタを適用(整形のみ)
a8661df Tanaka Aoi 2026-06-15 在庫少の基準を10個未満に変更
d8646ea Suzuki Ken 2026-05-11 税率を10%に変更
1347895 Sato Hana 2026-04-06 在庫計算の初版を追加
| コミット | 内容 |
|---|---|
1347895 |
stock.py と README.md を追加(初版) |
d8646ea |
TAX_RATE を 0.08 から 0.10 に変更 |
a8661df |
在庫少の基準を count < 5 から count < 10 に変更、README に1行追加 |
7b09ed3 |
インデントを4文字から2文字に、= の前後の空白を変更(整形のみ) |
adce066 |
判定を count < 10 から count <= 10 に変更 |
ca57ae7 |
format_item 関数を display.py へ移動 |
最新の stock.py は次の7行です。
TAX_RATE = 0.10
def total_price(price, count):
return price * count * (1 + TAX_RATE)
def is_low_stock(count):
return count <= 10
git showでコミットの内容を確認する
引数なしで最新のコミットを見る
git show
commit ca57ae74cc2fa3244ff3f4bb70f5a2be958fee8c
Author: Tanaka Aoi <aoi@example.com>
Date: Thu Sep 10 16:20:00 2026 +0900
format_itemをdisplay.pyへ移動
diff --git a/display.py b/display.py
new file mode 100644
index 0000000..dbd3c19
--- /dev/null
+++ b/display.py
@@ -0,0 +1,4 @@
+# 表示用の関数
+
+def format_item(name, count):
+ return f"{name}: {count}"
diff --git a/stock.py b/stock.py
index 312c443..0273bd5 100644
--- a/stock.py
+++ b/stock.py
@@ -5,6 +5,3 @@ def total_price(price, count):
def is_low_stock(count):
return count <= 10
-
-def format_item(name, count):
- return f"{name}: {count}"
git show は、引数を省くと HEAD(いまいる最新のコミット)を表示します。 コミットの ID を渡せば、そのコミットを表示します。
git show の出力の読み方
| 行 | 意味 |
|---|---|
commit ca57ae74... |
コミットの ID(40文字のハッシュ)。先頭7文字ほどで指定できる |
Author: |
変更を書いた人の名前とメールアドレス |
Date: |
作成日時(Author の日時) |
| 空行の後の字下げされた行 | コミットメッセージ。変更の理由はここに書かれている |
diff --git a/stock.py b/stock.py |
ここから stock.py の差分が始まる |
new file mode 100644 |
新しく追加されたファイル |
--- a/stock.py と +++ b/stock.py |
変更前(a)と変更後(b)のファイル |
@@ -5,6 +5,3 @@ |
変更前は5行目から6行、変更後は5行目から3行の範囲を表示している |
先頭が - の行 |
削除された行 |
先頭が + の行 |
追加された行 |
| 先頭が空白の行 | 変更のない前後の行(文脈) |
ファイル名だけ・統計だけを見る
差分が長いコミットでは、まず全体の輪郭をつかむと読みやすくなります。
git show --name-only a8661df
commit a8661dfa8742684e84ed744069a17f3de5b95c1e
Author: Tanaka Aoi <aoi@example.com>
Date: Mon Jun 15 09:15:00 2026 +0900
在庫少の基準を10個未満に変更
README.md
stock.py
git show --stat a8661df
(commit から件名までは上と同じ)
README.md | 1 +
stock.py | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
--stat の 1 + は1行追加、2 +- は「追加1行・削除1行で合計2行」という意味です。追加・変更・削除の種別を知りたいときは --name-status を使います。
git show --name-status ca57ae7
(commit から件名までは省略)
A display.py
M stock.py
| 記号 | 意味 |
|---|---|
A |
追加(Added) |
M |
変更(Modified) |
D |
削除(Deleted) |
R |
名前変更(Renamed) |
ヘッダーを1行に縮めたいときは --oneline を組み合わせます。
git show --stat --oneline ca57ae7
ca57ae7 format_itemをdisplay.pyへ移動
display.py | 4 ++++
stock.py | 3 ---
2 files changed, 4 insertions(+), 3 deletions(-)
特定のファイルの差分だけを見る
コミット ID の後ろに -- とパスを書くと、そのファイルの差分だけに絞れます。
git show a8661df -- README.md
(commit から件名までは省略)
diff --git a/README.md b/README.md
index dad1e2a..de69b86 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
# stock
+在庫が少ないときに知らせます。
stock.py の差分は表示されず、README.md の分だけになりました。
差分を出さずに、誰がいつ変更したかだけを見る
-s(--no-patch)で差分を省き、--format で欲しい項目だけを並べます。
git show -s --format="%h %an <%ae> %ad%n%s" --date=iso a8661df
a8661df Tanaka Aoi <aoi@example.com> 2026-06-15 09:15:00 +0900
在庫少の基準を10個未満に変更
| 指定子 | 意味 | 指定子 | 意味 |
|---|---|---|---|
%H |
コミット ID(40文字) | %h |
コミット ID(短縮) |
%an |
作成者の名前 | %ae |
作成者のメールアドレス |
%ad |
作成日時(--date の形式に従う) |
%cd |
コミット日時 |
%cn |
コミッタの名前 | %s |
件名(メッセージの1行目) |
%n |
改行 | %b |
メッセージの本文 |
作成者(Author)は変更を書いた人、コミッタ(Committer)はそれを履歴に取り込んだ人です。リベースやチェリーピックをすると、コミッタとコミット日時だけが変わります。両方を並べて確認することもできます。
git show -s --format="%H%n作成者: %an <%ae>%n作成日: %ad%nコミッタ: %cn%nコミット日: %cd%n件名: %s" --date=iso adce066
adce066d9a1aa5cb8fe94fe15348b82c1c391b80
作成者: Sato Hana <hana@example.com>
作成日: 2026-08-20 11:45:00 +0900
コミッタ: Sato Hana
コミット日: 2026-08-20 11:45:00 +0900
件名: 在庫少の判定を10個以下に修正
その時点のファイルの中身を丸ごと見る
コミット:パス の形で渡すと、差分ではなくそのコミット時点のファイル全体が表示されます。
git show d8646ea:stock.py
TAX_RATE = 0.10
def total_price(price, count):
return price * count * (1 + TAX_RATE)
def is_low_stock(count):
return count < 5
def format_item(name, count):
return f"{name}: {count}"
ブランチを切り替えずに過去の内容を確かめられるので、git show d8646ea:stock.py > old_stock.py のようにファイルへ書き出して見比べる使い方もできます。
空白だけの変更を除く(-w)と単語単位の差分(--word-diff)
整形のコミット 7b09ed3 をそのまま表示すると、ほぼ全行が変更として出ます。
@@ -1,10 +1,10 @@
-TAX_RATE = 0.10
+TAX_RATE = 0.10
def total_price(price, count):
- return price * count * (1 + TAX_RATE)
+ return price * count * (1 + TAX_RATE)
(以下略)
-w を付けると、空白の違いだけの行は差分から外れます。
git show -w 7b09ed3
commit 7b09ed32f11bbe99e7e9b82e442ca9c5e7f7f86b
Author: Suzuki Ken <ken@example.com>
Date: Wed Jul 1 18:00:00 2026 +0900
フォーマッタを適用(整形のみ)
差分が1行も表示されませんでした。-w で差分が空になるコミットは、空白以外に変更がないと判断できます。
1行の中のどこが変わったかを見たいときは --word-diff が読みやすい表示になります。
git show --word-diff d8646ea
@@ -1,4 +1,4 @@
TAX_RATE = [-0.08-]{+0.10+}
[-...-] が削除された語、{+...+} が追加された語です。
git blameで各行を誰がいつ変更したかを確認する
git blame stock.py
7b09ed32 (Suzuki Ken 2026-07-01 18:00:00 +0900 1) TAX_RATE = 0.10
^1347895 (Sato Hana 2026-04-06 10:00:00 +0900 2)
^1347895 (Sato Hana 2026-04-06 10:00:00 +0900 3) def total_price(price, count):
7b09ed32 (Suzuki Ken 2026-07-01 18:00:00 +0900 4) return price * count * (1 + TAX_RATE)
^1347895 (Sato Hana 2026-04-06 10:00:00 +0900 5)
^1347895 (Sato Hana 2026-04-06 10:00:00 +0900 6) def is_low_stock(count):
adce066d (Sato Hana 2026-08-20 11:45:00 +0900 7) return count <= 10
git blame の出力の各列の読み方
7行目を例に、左から順に分解します。
adce066d (Sato Hana 2026-08-20 11:45:00 +0900 7) return count <= 10
───┬──── ─────┬──── ───────────┬───────────── ┬ ─────────┬────────
│ │ │ │ └ ⑤ その行の内容
│ │ │ └ ④ 現在のファイルでの行番号
│ │ └ ③ その変更の作成日時とタイムゾーン
│ └ ② 作成者の名前
└ ① その行を最後に変更したコミットの ID(先頭8文字)
| 列 | 内容 | 補足 |
|---|---|---|
| ① コミット ID | その行を最後に変更したコミット | git show adce066d に渡せば内容を読める |
| ② 作成者 | そのコミットの Author | -e を付けるとメールアドレス表示になる |
| ③ 日時 | 作成日時 | --date=short で日付だけにできる |
| ④ 行番号 | いまのファイルでの行番号 | -n を付けると元のコミットでの行番号も出る |
| ⑤ 内容 | その行のテキスト | |
先頭の ^ |
境界コミット | 調べた範囲のいちばん端(ここでは最初のコミット)で入った行 |
blame が示すのは「その行を最後に変更したコミット」です。 1行目と4行目が 7b09ed32(整形のコミット)になっているのは、空白を変えただけでも「その行を最後に変更した」ことになるためです。これをどう読み飛ばすかが、blame を使いこなす要点になります。
表示を短くする
| オプション | 効果 | 実行結果の例(1行分) |
|---|---|---|
| なし | 名前・日時つき | 7b09ed32 (Suzuki Ken 2026-07-01 18:00:00 +0900 1) TAX_RATE = 0.10 |
--date=short |
日付だけ | 7b09ed32 (Suzuki Ken 2026-07-01 1) TAX_RATE = 0.10 |
-s |
名前と日時を省く | 7b09ed32 1) TAX_RATE = 0.10 |
-e |
メールアドレス表示 | 7b09ed32 (<ken@example.com> 2026-07-01 18:00:00 +0900 1) TAX_RATE = 0.10 |
以降の実行結果は、横幅を抑えるために --date=short を付けています。
行範囲を絞る(-L)
大きなファイルでは、見たい行だけに絞ると速く、読みやすくなります。
git blame -L 6,7 stock.py
^1347895 (Sato Hana 2026-04-06 10:00:00 +0900 6) def is_low_stock(count):
adce066d (Sato Hana 2026-08-20 11:45:00 +0900 7) return count <= 10
| 書き方 | 意味 |
|---|---|
-L 6,7 |
6行目から7行目 |
-L 6,+2 |
6行目から2行分 |
-L '/def is_low/,/return/' |
正規表現に一致する行から、次に一致する行まで |
-L :is_low_stock |
関数名で指定(関数の先頭から終わりまで) |
関数名での指定も同じ結果になりました。
git blame -L :is_low_stock stock.py
^1347895 (Sato Hana 2026-04-06 10:00:00 +0900 6) def is_low_stock(count):
adce066d (Sato Hana 2026-08-20 11:45:00 +0900 7) return count <= 10
存在しない行を指定すると、次のように教えてくれます。
$ git blame -L 20,25 stock.py
fatal: file stock.py has only 7 lines
空白だけの変更を無視する(-w)
git blame -w --date=short stock.py
d8646ea4 (Suzuki Ken 2026-05-11 1) TAX_RATE = 0.10
^1347895 (Sato Hana 2026-04-06 2)
^1347895 (Sato Hana 2026-04-06 3) def total_price(price, count):
^1347895 (Sato Hana 2026-04-06 4) return price * count * (1 + TAX_RATE)
^1347895 (Sato Hana 2026-04-06 5)
^1347895 (Sato Hana 2026-04-06 6) def is_low_stock(count):
adce066d (Sato Hana 2026-08-20 7) return count <= 10
-w なしでは 7b09ed32(整形)だった1行目と4行目が、中身を実際に書き換えたコミット(1行目は税率変更の d8646ea4、4行目は初版の 1347895)に変わりました。インデントの変更やタブとスペースの変換が挟まっているファイルでは、まず -w を付けてみるのがおすすめです。
別ファイルから移動した行を追う(-M と -C)
format_item 関数は、最後のコミットで stock.py から display.py へ移されています。display.py をそのまま blame すると、すべての行が移動のコミットになります。
git blame --date=short display.py
ca57ae74 (Tanaka Aoi 2026-09-10 1) # 表示用の関数
ca57ae74 (Tanaka Aoi 2026-09-10 2)
ca57ae74 (Tanaka Aoi 2026-09-10 3) def format_item(name, count):
ca57ae74 (Tanaka Aoi 2026-09-10 4) return f"{name}: {count}"
ここで -C を付けましたが、今回の例では結果は変わりませんでした。-C -C、-C -C -C も同じです。理由はしきい値にあります。git-blame のドキュメントによると、-C が「移動・コピー」とみなすのは既定で英数字40文字以上のかたまりで、今回動かした2行はそれより短いためです。しきい値を20文字に下げると検出されました。
git blame -C20 --date=short display.py
ca57ae74 display.py (Tanaka Aoi 2026-09-10 1) # 表示用の関数
^1347895 stock.py (Sato Hana 2026-04-06 2)
^1347895 stock.py (Sato Hana 2026-04-06 3) def format_item(name, count):
7b09ed32 stock.py (Suzuki Ken 2026-07-01 4) return f"{name}: {count}"
コミット ID の右に「元のファイル名」の列が増え、3行目は stock.py の初版で書かれた行だとわかります。 4行目は整形のコミットになっていますが、git blame -w -C20 display.py と -w を組み合わせると、4行目も初版の 1347895 までさかのぼれました。
| オプション | 探す範囲 | 既定のしきい値 |
|---|---|---|
-M |
同じファイルの中での移動・コピー | 英数字20文字 |
-C |
同じコミットで変更された別のファイルからの移動・コピー | 英数字40文字 |
-C -C |
上に加えて、ファイルを作成したコミットでは他のファイルも探す | 同上 |
-C -C -C |
すべてのコミットで他のファイルを探す | 同上 |
-C20 のように数字を付ける |
しきい値を変える | 指定した文字数 |
-C を重ねるほど探す範囲が広がり、そのぶん時間がかかります。短い関数の移動を追うときは、重ねるよりもしきい値を下げるほうが効くことを、今回の結果が示しています。
過去の時点で blame する
ファイル名の前にコミットを書くと、その時点のファイルに対して blame できます。
git blame --date=short -L 7,7 adce066^ -- stock.py
7b09ed32 (Suzuki Ken 2026-07-01 7) return count < 10
adce066^ は「adce066 の1つ前(親)のコミット」という意味です。この書き方が、後半の「再 blame」の手順の中心になります。
整形コミットを飛ばす(--ignore-rev と --ignore-revs-file)
フォーマッタを一括で適用したコミットがあると、blame の結果がそのコミットで埋まります。-w は空白の違いだけを無視しますが、改行位置の変更や引用符の統一のような整形には効きません。コミットそのものを「なかったこと」として扱うのが --ignore-rev です。
git blame --date=short --ignore-rev 7b09ed3 stock.py
d8646ea4 (Suzuki Ken 2026-05-11 1) TAX_RATE = 0.10
^1347895 (Sato Hana 2026-04-06 2)
^1347895 (Sato Hana 2026-04-06 3) def total_price(price, count):
^1347895 (Sato Hana 2026-04-06 4) return price * count * (1 + TAX_RATE)
^1347895 (Sato Hana 2026-04-06 5)
^1347895 (Sato Hana 2026-04-06 6) def is_low_stock(count):
adce066d (Sato Hana 2026-08-20 7) return count <= 10
整形のコミット 7b09ed32 が消え、1つ前のコミットに割り当てられました。
無視するコミットをファイルにまとめる
毎回オプションで指定する代わりに、ファイルに書いてリポジトリで共有できます。ファイル名は自由ですが、.git-blame-ignore-revs という名前がよく使われます。
git rev-parse 7b09ed3 # 40文字の ID を調べる
7b09ed32f11bbe99e7e9b82e442ca9c5e7f7f86b
.git-blame-ignore-revs の中身:
# フォーマッタを適用(整形のみ)
7b09ed32f11bbe99e7e9b82e442ca9c5e7f7f86b
git blame --date=short --ignore-revs-file .git-blame-ignore-revs stock.py
結果は --ignore-rev 7b09ed3 のときと同じ7行になりました。ファイルには省略しない40文字の ID を1行に1つ書きます。 # で始まる行はコメントです。短縮した ID を書いて試すと、次の表示で止まりました。
$ git blame --ignore-revs-file bad stock.py
fatal: invalid object name: 7b09ed3
設定に登録して、オプションなしで効かせる
git config blame.ignoreRevsFile .git-blame-ignore-revs
git blame --date=short stock.py
設定後は、オプションを付けない git blame でも整形コミットが飛ばされ、上と同じ結果になりました。この設定はリポジトリごとの .git/config に入るので、ファイルをコミットして共有したうえで、各自が1回このコマンドを実行します。
飛ばされた行に印を付ける
blame.markIgnoredLines を有効にすると、無視したコミットを飛ばして割り当てられた行に ? が付きます。
git config blame.markIgnoredLines true
git blame --date=short stock.py
?d8646ea (Suzuki Ken 2026-05-11 1) TAX_RATE = 0.10
^1347895 (Sato Hana 2026-04-06 2)
^1347895 (Sato Hana 2026-04-06 3) def total_price(price, count):
^?134789 (Sato Hana 2026-04-06 4) return price * count * (1 + TAX_RATE)
^1347895 (Sato Hana 2026-04-06 5)
^1347895 (Sato Hana 2026-04-06 6) def is_low_stock(count):
adce066d (Sato Hana 2026-08-20 7) return count <= 10
1行目と4行目に ? が付き、「この行は整形コミットを飛ばした結果です」と読み取れます。
| 設定・オプション | 効果 |
|---|---|
--ignore-rev <コミット> |
そのコミットの変更をなかったものとして blame する。複数回指定できる |
--ignore-revs-file <ファイル> |
無視するコミットの一覧をファイルから読む |
blame.ignoreRevsFile |
上のファイルを設定に登録する |
blame.markIgnoredLines |
飛ばして割り当てた行に ? を付ける |
blame.markUnblamableLines |
飛ばした先を特定できなかった行に * を付ける(未実行。git-blame のドキュメントで確認) |
-w と --ignore-rev の使い分け
| 状況 | 向いている方法 |
|---|---|
| インデントや空白だけが変わった | -w |
| フォーマッタで改行位置や引用符まで変わった | --ignore-rev / --ignore-revs-file |
| チーム全員で同じ結果を見たい | .git-blame-ignore-revs をコミットし、blame.ignoreRevsFile を設定 |
| 中身の変更と整形が1つのコミットに混ざっている | 飛ばさずに、次の git log -L で履歴を全部見る |
行の履歴をまとめて追う(git log -L)
blame は「最後の変更」を1つだけ教えてくれます。その行がこれまでどう変わってきたかを全部見たいときは git log -L を使います。
git log -L 7,7:stock.py --format="%h %an %ad %s" --date=short
adce066 Sato Hana 2026-08-20 在庫少の判定を10個以下に修正
diff --git a/stock.py b/stock.py
--- a/stock.py
+++ b/stock.py
@@ -7,1 +7,1 @@
- return count < 10
+ return count <= 10
7b09ed3 Suzuki Ken 2026-07-01 フォーマッタを適用(整形のみ)
diff --git a/stock.py b/stock.py
--- a/stock.py
+++ b/stock.py
@@ -7,1 +7,1 @@
- return count < 10
+ return count < 10
a8661df Tanaka Aoi 2026-06-15 在庫少の基準を10個未満に変更
diff --git a/stock.py b/stock.py
--- a/stock.py
+++ b/stock.py
@@ -7,1 +7,1 @@
- return count < 5
+ return count < 10
1347895 Sato Hana 2026-04-06 在庫計算の初版を追加
diff --git a/stock.py b/stock.py
--- /dev/null
+++ b/stock.py
@@ -0,0 +7,1 @@
+ return count < 5
7行目が「5未満 → 10未満 →(整形)→ 10以下」と変わってきた流れが、1回のコマンドで新しい順に並びました。blame と親コミットへの再 blame を繰り返す作業を、まとめて済ませられます。
関数名でも指定できます。-s を付けると差分を省いて一覧だけになります。
git log -L :is_low_stock:stock.py --oneline -s
adce066 在庫少の判定を10個以下に修正
7b09ed3 フォーマッタを適用(整形のみ)
a8661df 在庫少の基準を10個未満に変更
1347895 在庫計算の初版を追加
| 書き方 | 意味 |
|---|---|
git log -L 7,7:stock.py |
stock.py の7行目の履歴 |
git log -L 6,+2:stock.py |
6行目から2行分の履歴 |
git log -L :is_low_stock:stock.py |
関数 is_low_stock の履歴 |
git log -L '/def is_low/,/return/:stock.py' |
正規表現で範囲を指定(関数名指定と同じ4件が表示された) |
文字列の出現を追う(git log -S と -G)
「この値はいつ入ったのか」「消えた記述はどのコミットでなくなったのか」を調べるときは、行番号ではなく文字列で探します。
-S:文字列の出現回数が変わったコミットを探す
git log -S "0.08" --oneline
d8646ea 税率を10%に変更
1347895 在庫計算の初版を追加
0.08 が最初に入ったコミット(初版)と、なくなったコミット(税率変更)の2つが見つかりました。いまのファイルには残っていない文字列でも探せるのが、blame にはない強みです。 -p を付けると差分も一緒に表示されます。
git log -S "0.08" --format="%h %an %ad %s" --date=short -p -- stock.py
d8646ea Suzuki Ken 2026-05-11 税率を10%に変更
diff --git a/stock.py b/stock.py
index c8844ed..1d75fce 100644
--- a/stock.py
+++ b/stock.py
@@ -1,4 +1,4 @@
-TAX_RATE = 0.08
+TAX_RATE = 0.10
(以下略)
-G:差分の中に文字列(正規表現)が出てくるコミットを探す
-S と -G は似ていますが、結果が分かれる場面があります。同じ文字列で比べました。
git log -S "count <" --oneline
1347895 在庫計算の初版を追加
git log -G "count <" --oneline
adce066 在庫少の判定を10個以下に修正
7b09ed3 フォーマッタを適用(整形のみ)
a8661df 在庫少の基準を10個未満に変更
1347895 在庫計算の初版を追加
-S は1件、-G は4件です。count < 5 が count < 10 に変わったコミットでは、count < という文字列の個数は1個のままなので、-S には出てきません。一方 -G は、追加・削除された行のどこかにその文字列があれば拾います。
TAX_RATE でも同じ違いが出ました。
| 検索 | 結果 |
|---|---|
git log -S "TAX_RATE" --oneline |
1347895 の1件(初めて入ったコミット) |
git log -G "TAX_RATE" --oneline |
7b09ed3・d8646ea・1347895 の3件(その行に触れたコミットすべて) |
| 比べる点 | -S "文字列" |
-G "正規表現" |
|---|---|---|
| 拾う条件 | その文字列の出現回数が増減したコミット | 追加・削除された行に一致があるコミット |
| 向いている問い | いつ入った? いつ消えた? | この記述に触れた変更をすべて見たい |
| 引数の扱い | 既定はそのままの文字列 | 正規表現 |
| 同じ行の中で値だけ変わったとき | 拾わない | 拾う |
-S を正規表現で使いたいときは --pickaxe-regex を付けます。
git log -S "return count <= [0-9]+" --pickaxe-regex --oneline
adce066 在庫少の判定を10個以下に修正
blame → show → 親コミットへ再blameの調査手順
ここまでの道具をつなげて、「stock.py の7行目 return count <= 10 は、どういう経緯でこうなったのか」を調べます。
flowchart TD
A[1. git blame -L で行のコミットを特定] --> B[2. git show でコミットの内容と理由を読む]
B --> C{知りたい変更だった?}
C -->|はい| D[調査完了]
C -->|いいえ・もっと前を知りたい| E[3. git blame コミット^ -- ファイル で親から再 blame]
E --> B
手順1:blame で行のコミットを特定する
git blame --date=short -L 7,7 stock.py
adce066d (Sato Hana 2026-08-20 7) return count <= 10
手順2:show でそのコミットの内容と理由を読む
git show --stat --oneline adce066
git show adce066 -- stock.py
adce066 在庫少の判定を10個以下に修正
stock.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(2つ目のコマンドの差分部分を抜粋)
def is_low_stock(count):
- return count < 10
+ return count <= 10
< が <= に変わったコミットだとわかりました。では、その前の「10」という基準はいつ決まったのでしょうか。
手順3:親コミットへ再 blame する
コミット ID に ^ を付けて、そのコミットの直前の状態に対して同じ行を blame します。
git blame --date=short -L 7,7 adce066^ -- stock.py
7b09ed32 (Suzuki Ken 2026-07-01 7) return count < 10
整形のコミットに当たりました。もう一度、その親へさかのぼります。
git blame --date=short -L 7,7 7b09ed3^ -- stock.py
a8661dfa (Tanaka Aoi 2026-06-15 7) return count < 10
a8661df「在庫少の基準を10個未満に変更」が、基準を10にしたコミットでした。さらにさかのぼると初版に着きます。
git blame --date=short -L 7,7 a8661df^ -- stock.py
^1347895 (Sato Hana 2026-04-06 7) return count < 5
先頭に ^ が付いたら、それより前の履歴はありません。
整形コミットを1回で飛び越える
手順3で整形コミットに当たったときは、-w を付けると1回で飛び越えられました。
git blame --date=short -w -L 7,7 adce066^ -- stock.py
a8661dfa (Tanaka Aoi 2026-06-15 7) return count < 10
コピペ用:調査の型
# 1. 行のコミットを特定(FILE と行番号を置き換える)
git blame -w --date=short -L 7,7 FILE
# 2. コミットの内容と理由を読む(COMMIT を置き換える)
git show --stat COMMIT
git show COMMIT -- FILE
# 3. もっと前を知りたいときは、親から再 blame(行番号がずれていたら調整)
git blame -w --date=short -L 7,7 COMMIT^ -- FILE
# まとめて履歴を見たいとき
git log -L 7,7:FILE --date=short
# いまは残っていない記述を探すとき
git log -S "探したい文字列" --oneline -- FILE
再 blame のときは、親コミットの時点では行番号がずれていることがある点に気を付けます。手順2の git show の差分にある @@ -7,1 +7,1 @@ の左側(-7)が、親コミットでの行番号です。行番号の調整が手間なときは、git log -L に切り替えると Git が自動で追ってくれます。
つまずきやすい表示と直し方
| 表示・状況 | 原因 | 直し方 |
|---|---|---|
fatal: no such path 'nofile.py' in HEAD |
ファイル名が違う、または HEAD に存在しない | パスを確認。削除済みのファイルは git blame コミット^ -- パス |
fatal: file stock.py has only 7 lines |
-L の範囲がファイルの行数を超えている |
行番号を見直す |
fatal: ambiguous argument 'zzzz': unknown revision or path not in the working tree. |
コミット ID やブランチ名が見つからない | git log --oneline で ID を確認 |
fatal: invalid object name: 7b09ed3 |
ignore-revs ファイルに短縮 ID を書いた | git rev-parse で40文字の ID を調べて書く |
| すべての行が同じコミットになる | 整形や移動のコミットが最後に入っている | -w、--ignore-rev、-C を試す |
-C を付けても変わらない |
移動した量がしきい値(英数字40文字)より少ない | -C20 のようにしきい値を下げる |
コミット ID の先頭に ^ が付く |
履歴の端(最初のコミットなど)で入った行 | そのまま読んでよい。浅いクローンなら履歴を取得し直す |
上の表のエラー文は、いずれも今回の検証で実際に表示されたものです。
よくある質問
Q. git blame という名前ですが、人を責めるためのコマンドですか?
A. いいえ。目的は「この行がなぜこうなっているのか」を知ることです。コミット ID がわかれば、git show でコミットメッセージと差分を読めますし、書いた人に背景を尋ねる手がかりにもなります。経緯を知るための道具として使うのがおすすめです。
Q. 削除された行は、誰がいつ消したのかを調べられますか?
A. blame はいま存在する行を対象にするので、消えた行には git log -S "消えた文字列" を使います。今回の例では git log -S "0.08" で、0.08 を入れたコミットとなくしたコミットの両方が見つかりました。
Q. git show と git log -p はどう違いますか?
A. git show は指定した1つのコミット(省略時は HEAD)を表示し、git log -p は履歴をさかのぼりながら複数のコミットを差分つきで表示します。コミット ID がわかっているなら show、範囲で眺めたいなら log -p が向いています。
Q. GitHub の画面で見る blame にも、整形コミットを飛ばす設定は効きますか?
A. リポジトリの直下に .git-blame-ignore-revs という名前でファイルを置くと、GitHub の blame 表示でも使われることが一般に知られています(この記事では GitHub 上での動作は未実行です)。手元の Git では、git config blame.ignoreRevsFile .git-blame-ignore-revs を各自で設定します。
まとめ
- git show はコミットを起点に「何が変わったか」、git blame は行を起点に「誰がいつ変更したか」を表示する
- show は
--stat・--name-only・-- パス・-s --formatで、見たい粒度に絞れる - blame の各列は「コミット ID・作成者・日時・行番号・内容」。先頭の
^は履歴の端で入った行 - 空白だけの変更は
-w、整形コミット全体は--ignore-revs-fileとblame.ignoreRevsFileで飛ばせる - 移動した行は
-Cで追える。短い関数は-C20のようにしきい値を下げると検出される - 行の履歴をまとめて見るなら
git log -L、消えた文字列を探すならgit log -S、触れた変更を全部拾うなら-G - 調査の型は「blame で特定 → show で理由を読む →
コミット^で親へ再 blame」
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「git showとgit blameの使い方|誰がいつ変更したかを確認する」
株式会社RJCでは、git showやgit blameを使った変更履歴の調べ方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。