GitSearching History (git log -S, -G)

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

-S "string"

Commits where the count of occurrences of string differs between before and after

A commit matches only if the number of times string appears changed

-G "regex"

Commits where any added or removed line matches regex

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

Bash
git log -S "SecretAPIKey" --oneline

Sample output

Text
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:

Bash
git log -S "SecretAPIKey" -p

-p shows the diff for each matching commit

Text
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

Bash
# 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

Bash
# Make -S treat its argument as a regex
git log -S "MAX_(RETRIES|TRIES)" --pickaxe-regex --oneline

# Useful when you&apos;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:

Bash
git log -S "SecretAPIKey" -p --pickaxe-all
Real-world recipes

Recipe 1 — When was this function introduced?

Bash
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?

Bash
git log -S ".legacy-header" -p -- "*.css" "*.scss"
# Look for the commit where the count went from N to 0 — that&apos;s the deletion.

Recipe 3 — When did we change a magic number?

Bash
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

Bash
git log --follow -S "function authenticate" -p -- src/

Recipe 5 — Find every commit that touched a hard-coded URL

Bash
git log -S "https://internal-api.example.com" --oneline
Combining with other filters

Bash
# 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 foo to bar and another spot adds a foo, the count of foo may not change — -S "foo" could miss it. Use -G for 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 match foo 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 grep instead.

Pickaxe vs grep vs blame

Question

Tool

Where does this string appear right now?

git grep

Which commit introduced or removed this string?

git log -S

Which commits ever touched a line matching this regex?

git log -G

Who last edited this line and why?

git blame

How did this function evolve over time?

git log -L :func:file

Pickaxe is the time-machine of search
Once you know `git log -S` exists, you stop asking "when did this happen?" and start *answering* it in 5 seconds. Combined with `-p`, it's how you read the historical why behind any line of code that survived a hundred refactors.
Tip
Pair the pickaxe with `git show` for the final write-up. A recipe like 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.