one binary,
four ways to ask.
when did this string appear?
runs git log --all -S and prints every commit that introduced or removed an exact string — oldest first.
$ gitwhen "TODO: deprecated"● a3c4b18 2026-03-14 alice — drop legacy queue path ● 7f1e602 2025-11-08 bob — TODO before refactor
what commit set this line?
parses git blame --porcelain for one line. you get hash, author, date, subject, and the line itself — nothing else to read.
$ gitwhen src/auth.ts:42 a3c4b18 2026-03-14 alice drop legacy queue path │ if (!ctx.session) throw …
full life of a file
first-added, every delete, every re-add, last-touched. uses --diff-filter=A/D across all branches.
$ gitwhen --file legacy.py+ first added 8a91c0e 2024-06-12 bob — initial port × deleted 1d4e88f 2025-09-04 alice — sunset legacy/
regex variant
same as string but with -G instead of -S — for “any console.log of pii” rather than one literal token.
$ gitwhen --regex \ "console\.log\(.*pii.*\)"● 9c0a2d1 2024-08-22 carol — debug pii leak ● 7f1e602 2024-06-30 bob — temporary trace
three places
it earns its keep.
npm
$ npm i -g @v0idd0/gitwhen
node 14+ on linux / macos / windows. zero runtime deps. needs git on $PATH.
regression guardrail
$ gitwhen --json \
"OLD_DEPRECATED_API" \
| jq -e '.count == 0' \
|| (echo "deprecated api is back"; exit 1)
drop into ci. blocks any branch that re-introduces a string you deliberately removed.
incident archaeology
$ gitwhen "$BAD_FUNCTION_NAME"
"when did this regression land?" is the most common p0 question. answer it without leaving the terminal.
we googled "git log -S" for the eighth quarter in a row. that's when we accepted that the tool wasn't the bottleneck — the muscle memory was. so we wrapped it.
no telemetry. no signup. no “upgrade for the enterprise rule pack.” mit forever, even if vøiddo dies tomorrow — the source is public and the npm package is yours to fork.