15
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HRBrainAdvent Calendar 2024

Day 5

【Git】どのコミットでバグが生まれたのか?git log -Sで探したいコミットを爆速で見つける!

Last updated at Posted at 2024-12-05

はじめに

こんにちは、ken です!

開発中に次のような疑問を抱くことってありませんか?

  • 「このコード、いつ追加されたんだろう?」
  • 「この関数が削除されたのはなぜ?」

Git にはこうした疑問を解消する便利なコマンドがあります、それがgit log -Sです!
本記事では、このコマンドの基本から具体的な使い方までを解説してみようと思います。

git log -Sとは

git log -Sとはどういったコマンドなのでしょうか。以下にGit の公式ドキュメントの説明を引用します。

Look for differences that change the number of occurrences of the specified string (i.e. addition/deletion) in a file. Intended for the scripter’s use.

It is useful when you’re looking for an exact block of code (like a struct), and want to know the history of that block since it first came into being: use the feature iteratively to feed the interesting block in the preimage back into -S, and keep going until you get the very first version of the block.

Binary files are searched as well.

(筆者による日本語訳)
ファイル中の指定された文字列の出現回数(追加/削除など)を変更する差分を検索する。スクリプト作成者向けに設計されています。

コードの正確なブロック(構造体など)を探し、そのブロックが最初に作成されてからの履歴を知りたい場合に便利です。この機能を繰り返し使用して、プリイメージ内の関連あるブロックにフィードバックします。-S やロックの最初のバージョンを取得するまで続けます。
構造体のような特定のコードブロックを正確に検索し、そのブロックが初めて作成された時点からの履歴を確認したい場合に便利です。この機能を繰り返し使用し、興味のあるブロックを前の状態から抽出して -S オプションに入力し続けることで、そのブロックが最初に現れたバージョンまで遡ることができます。

バイナリファイルも検索対象に含まれます。

ファイル内の指定された文字列の出現回数の変更を探し出す、というのが少し聞き慣れない表現ですが、要するに特定の文字列が「追加」または「削除」されたコミットを探すためのコマンドということです。
言葉だけでは分かりにくいと思うので、実際に具体例を見てみましょう!

簡単な具体例

math.go
package math

func Add(a int, b int) int {
    return a + b
}

func Subtract(a int, b int) int {
    return a - b
}

例えば上のようなコードがあったとします。
Subtract関数はいつ、どのコミットで追加されたのか?」と思ったときに、git log -Sが活躍します。

コマンドの実行

次のようにコマンドを実行します。

git log -S "func Subtract" -- math.go

各オプションの意味は以下のとおりです。

  • -S "func Subtract"で、検索する文字列を指定
  • -- math.go:検索対象を特定のファイルに絞る(省略時はリポジトリ全体を対象にして検索します)

実行結果

以下のようなログが出力されます。

commit 89517ecb54e3e13a54e67a26dbccc546d0f37d35 (HEAD -> master)
Author: Ken <qiita_ken@example.com>
Date:   Sat Nov 30 19:52:42 2024 +0900

    add Subtract function to math.go

この結果から、「Subtract関数が追加されたのは89517ecbというコミットである」とわかりました!

もっと詳しく表示する

コミットの詳細を確認したい場合は、以下のコマンドを実行します。

git show 89517ecb

皆さんおなじみのgit showですね!
実行後出力されるこのコミットメッセージと差分から、Subtract関数がいつどのように実装されたかがわかります。

commit 89517ecb54e3e13a54e67a26dbccc546d0f37d35 (HEAD -> master)
Author: Ken <qiita_ken@example.com>
Date:   Sat Nov 30 19:52:42 2024 +0900

    add Subtract function to math.go

diff --git a/math/math.go b/math/math.go
index f486ea3..bbe266a 100644
--- a/math/math.go
+++ b/math/math.go
@@ -3,3 +3,7 @@ package math
 func Add(a int, b int) int {
        return a + b
 }
+
+func Subtract(a int, b int) int {
+       return a - b
+}

また、冒頭で述べたとおり、git log -Sは、「特定の文字列が『追加』または『削除』されたコミットを探すためのコマンド」なので、削除されたコードを追跡したいときも同じコマンドを使います。つまりSubtract 関数が削除されていた場合も、先ほどと同じコマンドで履歴を追うことができるというわけです。

git log -S "func Subtract" -- math.go

結果には、追加時と削除時の両方のコミットが表示されます。

commit 4f82fdbd6eb0885cacc10001568a17545f284a04 (HEAD -> master)
Author: Ken <qiita_ken@example.com>
Date:   Sun Dec 1 00:52:06 2024 +0900

    remove Subtract function from math.go

commit 89517ecb54e3e13a54e67a26dbccc546d0f37d35
Author: Ken <qiita_ken@example.com>
Date:   Sat Nov 30 19:52:42 2024 +0900

    add Subtract function to math.go

より実用的な具体例

ここまではひとまずgit log -Sを理解するために簡単な具体例を扱いましたが、ここからはより実用的な使い方を 2 つ紹介します。

削除された機能の履歴を追跡する

「昔あったはずの API エンドポイント(例: /v1/legacy-endpoint)がなぜ消えたのか」を調査したいとします。
git log -Sは特定の文字列が削除されたコミットも探すことができるので、下のコマンドを叩いて出てきた最新のコミットを見れば削除された理由がわかるはずです。

git log -S "/v1/legacy-endpoint" -- app/api/*

バグを引き起こしたコミットを探す

「特定のバグが発生した原因となった変更を探りたい」とします。
例えばif user.IsAdmin()という条件が追加されていたことで、予期せぬ挙動が発生した場合、この条件分岐が追加されたコミットを確認することで、バグが生まれてしまった原因や、いつ頃からバグが発生していたのかを調べることができます。

git log -S "if user.IsAdmin()" -- app/domain/user.go

git blameとの違い

git blameでも同じことができるのでは?」と思う方もいるかもしれませんが、git blameには次の制約があります:

  • リポジトリ全体を検索できない
    • git blameは 1 ファイル単位でしか履歴を追えませんが、git log -Sは複数ファイルやリポジトリ全体を対象に検索可能です
  • 差分そのものを追いづらい
    • git blameの変更履歴は確認できますが、差分そのものや具体的な追加・削除の内容を調べることはできません

おまけ

ちなみにgit log -Sに似たコマンドとして、git log -Gもあります。(公式ドキュメント
-Sでは文字列の増減を追跡していたのに対して、-Gでは文字列を含む差分を追跡できます。
例えば、user.Roleを含む条件式の差分を追跡したいときは次のようなコマンドを叩けばよいです。git log -Gを使うときは正規表現で検索をかけます。1

git log -G "if .*user\.Role.*" -- app/domain/user.go

追加や削除だけでなく、より広く特定のパターンやロジックの変更を検索したいときはこちらのgit log -Gを使うと良さそうですね。

最後に

この記事ではgit log -Sの有用性について書いてみました。
海外の方の動画を見てこのコマンドを知ったのですが、記事を書くにあたってgit logのオプションを確認したら他にもたくさんあって驚きました...。

間違いなどありましたらコメント欄でご指摘いただければ幸いです。最後までお読みいただきありがとうございました。

PR

株式会社HRBrainでは、一緒に働く仲間を募集しています!
興味を持っていただけた方はぜひ弊社の採用ページをご確認ください!

  1. 一応git log -Sでも--pickaxe-regexオプションを併用することで正規表現を使うことは可能です。git log -S "<正規表現>" --pickaxe-regexの形で記述します。

15
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?