Searching History (git log -S, -G)
The "pickaxe" — git log -S and git log -G — searches through diffs, not commit messages. It answers questions like "when was this constant added?", "when did we delete this CSS class?", and "which commit introduced this function?" If git grep searches what the code looks like now, the pickaxe searches what changed across all of history.
-S versus -G
Flag | Searches for | How matches are counted |
|---|---|---|
| Commits where the count of occurrences of | A commit matches only if the number of times |
| Commits where any added or removed line matches | A commit matches if any +/- line contains the regex, even if the total count is unchanged |
Practical translation: use -S to find when text was actually introduced or deleted. Use -G to also find "edited" lines that contain the pattern.
Finding when text was added
git log -S "SecretAPIKey" --oneline
Sample output
a1b2c3d Remove legacy SecretAPIKey constant 9f8e7d6 Introduce SecretAPIKey for v1 auth
Two commits — the one that added it (9f8e7d6) and the one that removed it (a1b2c3d). Want to see the actual changes? Add -p:
git log -S "SecretAPIKey" -p
-p shows the diff for each matching commit
commit 9f8e7d6...
Author: Alice <alice@example.com>
Date: Mon Jan 15 10:00:00 2025 +0000
Introduce SecretAPIKey for v1 auth
diff --git a/src/auth.js b/src/auth.js
+ const SecretAPIKey = process.env.SECRET_API_KEY;Regex form with -G
# Any commit that added or removed a line matching this regex git log -G "function\s+login\b" --oneline # Same with case-insensitive search git log -i -G "TODO" --oneline # -G also matches MODIFIED lines that happen to contain the pattern, # whereas -S only fires when the COUNT of "login" changes.
Regex on -S
# Make -S treat its argument as a regex git log -S "MAX_(RETRIES|TRIES)" --pickaxe-regex --oneline # Useful when you're hunting a renamed constant
Showing all changes in matching commits
By default -p with -S only prints the file changes that actually contain the pickaxe term. To see the full diff of each matching commit (helpful when the change is split across files), add --pickaxe-all:
git log -S "SecretAPIKey" -p --pickaxe-all
Real-world recipes
Recipe 1 — When was this function introduced?
git log --diff-filter=A -S "function calculateTax" -p # --diff-filter=A narrows to commits that ADDED the file in question, # combined with -S finds the introducing commit even after refactors.
Recipe 2 — When was this CSS class removed?
git log -S ".legacy-header" -p -- "*.css" "*.scss" # Look for the commit where the count went from N to 0 — that's the deletion.
Recipe 3 — When did we change a magic number?
git log -G "MAX_RETRIES\s*=\s*[0-9]+" -p # -G catches every commit that changed the value, not just add/delete.
Recipe 4 — Track a function across renames
git log --follow -S "function authenticate" -p -- src/
Recipe 5 — Find every commit that touched a hard-coded URL
git log -S "https://internal-api.example.com" --oneline
Combining with other filters
# Pickaxe + author + date range git log -S "SecretAPIKey" \ --author="Alice" \ --since="2025-01-01" --until="2025-12-31" \ --oneline # Pickaxe + path restriction git log -S "TODO" -- "src/**/*.test.js" # Pickaxe + branch range git log v1.0..v2.0 -S "DEPRECATED_FLAG" --oneline
Limitations of pickaxe
Net-zero edits are invisible to -S. If a commit renames a variable from
footobarand another spot adds afoo, the count offoomay not change —-S "foo"could miss it. Use-Gfor that case.Pickaxe is line-based for -G. A multi-line construct that spans 3 lines won't match a 1-line regex.
Whitespace counts.
-S "foo bar"will not matchfoo bar. Combine with--pickaxe-regex -S "foo\s+bar"or use-G.Pickaxe is slower than
git log --grep. It walks every diff. On giant repos, narrow with paths or a date range.It searches diffs, not the working tree. To find current occurrences, use
git grepinstead.
Pickaxe vs grep vs blame
Question | Tool |
|---|---|
Where does this string appear right now? |
|
Which commit introduced or removed this string? |
|
Which commits ever touched a line matching this regex? |
|
Who last edited this line and why? |
|
How did this function evolve over time? |
|
git log -S "magic" --oneline | head -1 | awk '{print $1}' | xargs git show jumps you straight into the commit that first added the term. Save it as an alias once you find a shape you like.