Git blame tells you who. git-why tells you WHY.
The AI-powered git history explainer and commit explainer that turns archaeological code digs into human-readable narratives. Think of it as a git-blame-ai that actually explains the reasoning, not just the authorship.
You open a file. Line 87 has a bizarre regex. The variable name makes no sense. There's a try-catch wrapping a single assignment.
You run git blame. Now you know who wrote it and when. Congratulations β you still have no idea why.
You could dig through commit messages, PRs, and Slack history. Or you could:
git-why src/validators.js:87git-why analyzes git blame, commit messages, and diffs β then uses AI to explain the reasoning behind the code. It turns raw git history into a human-readable narrative.
π Git History Explanation
ββββββββββββββββββββββββββββββββββββββββββββββββ
This unusual email regex was added after discovering that
RFC 5322 validation rejected corporate emails with + signs
(e.g., "user+tag@company.com").
The commented-out "strict mode" was an attempted fix that
broke too many legitimate addresses in production β kept as
documentation of what NOT to do.
ββββββββββββββββββββββββββββββββββββββββββββββββ
Think of it as having a senior developer explain the archaeological layers of your codebase β except they actually read all the commit messages.
npm install -g git-whyOr run without installing:
npx git-why src/auth.js:42You need an Anthropic API key. Get one at console.anthropic.com.
export ANTHROPIC_API_KEY="sk-ant-..."Add to ~/.bashrc or ~/.zshrc to make it permanent.
# Explain a specific line
git-why src/auth.js:42
# Explain a range
git-why src/auth.js:42-58
# Explain a function
git-why --function validateUser src/auth.js
# Explain an entire file
git-why src/auth.js
# Multiple files at once
git-why src/auth.js src/utils.js src/api.jsYou find a 200-line payment handler full of null checks and retry logic. Before you "clean it up":
$ git-why --function handlePayment src/payment.jsπ Git History Explanation
ββββββββββββββββββββββββββββββββββββββββββββββββ
This payment handler accumulated defensive checks over time
due to several production incidents:
1. The null check for `amount` β added after undefined amounts
caused Stripe to charge $0.00, creating accounting chaos.
2. The retry logic β payment webhooks occasionally fail due to
network timeouts. Immediate retries succeed 90% of the time.
Without this, users saw "payment failed" despite successful charges.
3. The database transaction wrapper β added after a race condition
where duplicate form submissions created multiple charges.
Each "ugly" part solved a real production problem.
ββββββββββββββββββββββββββββββββββββββββββββββββ
Now you know the landmines before you refactor.
Reviewing a PR with suspicious-looking changes:
$ git-why src/api/rate-limiter.js:42π Git History Explanation
ββββββββββββββββββββββββββββββββββββββββββββββββ
This Redis-based rate limiter replaced an in-memory solution
after the app scaled to multiple servers.
The 60-second window / 100 request limit was chosen based on
actual API usage patterns β 99% of legitimate users make fewer
than 50 requests/minute, but bots exceed 200/minute.
The sliding window algorithm (vs fixed window) prevents the
"reset boundary exploit" where users could make 200 requests
in 2 seconds by timing requests around the minute boundary.
ββββββββββββββββββββββββββββββββββββββββββββββββ
New to the team. Everything looks like spaghetti:
$ git-why src/legacy/parser.jsπ Git History Explanation
ββββββββββββββββββββββββββββββββββββββββββββββββ
This parser handles data from an old third-party API
(deprecated 2024). It remains because:
1. 200+ customers still use the legacy integration
2. Migration is phased over 2 years
3. New code should use src/parsers/v2/ instead
The unusual regex patterns handle malformed XML from the old
vendor (who never fixed their output despite bug reports).
DO NOT refactor β this code is intentionally defensive and
will be removed entirely in Q4 2026.
ββββββββββββββββββββββββββββββββββββββββββββββββ
18 commits across 3 years, 4 contributors
$ git-why --verbose src/cache.js:67π Git History Explanation
ββββββββββββββββββββββββββββββββββββββββββββββββ
This cache invalidation is intentionally aggressive after
a production bug where stale data persisted for hours.
ββββββββββββββββββββββββββββββββββββββββββββββββ
Commits analyzed:
f3a7b2c1 - 2026-01-20 14:45
Alice Wong β Fix cache invalidation for nested relationships
Original implementation only cleared exact keys:
- cache.del(`user:${id}`)
But didn't clear related keys like user:{id}:posts,
user:{id}:settings β leading to stale data bugs.
d4e9c8b7 - 2025-11-12 09:23
Bob Smith β Add Redis caching layer
ββββββββββββββββββββββββββββββββββββββββββββββββ
$ git-why --json src/config.js:15 | jq -r '.explanation'Pipe to scripts, CI pipelines, or documentation generators:
# Generate history docs for core files
for file in src/core/*.js; do
git-why "$file" --json | jq -r '.explanation' >> docs/architecture-decisions.md
done- Git Blame β finds which commits touched the target code
- Git Log β pulls commit messages and diffs
- Context Analysis β gathers surrounding code for context
- AI Explanation β Claude analyzes everything and explains the "why"
Arguments:
target file:line, file:start-end, or file
Options:
-f, --function <name> Explain a specific function
-v, --verbose Show detailed commit history
--json Output as JSON
--no-color Disable colors
-V, --version Output version
-h, --help Display help
| git-why | git blame | git log | |
|---|---|---|---|
| Shows who | β | β | β |
| Shows when | β | β | β |
| Shows why | β | β | Sometimes |
| Human-readable narrative | β | β | β |
| Connects multiple commits | β | β | Manual |
| Function-level analysis | β | β | β |
| Works offline | β | β | β |
| Cost | ~$0.01/file | Free | Free |
Use git blame when you need quick authorship info.
Use git log when you need raw commit details.
Use git-why when you need to understand the reasoning and evolution behind code.
git config --global alias.why '!f() { git-why "$@"; }; f'Now: git why src/auth.js:42
{
"label": "git-why: Explain Current Line",
"type": "shell",
"command": "git-why ${relativeFile}:${lineNumber}"
}Cmd+Shift+P β "Run Task" β "git-why: Explain Current Line"
# Add to ~/.zshrc
gwhy() { git-why "$@"; }- Node.js 18+
- Git repository with at least one commit
- Anthropic API key
- Requires internet (API call to Claude)
- Doesn't follow file renames (yet)
- Can't explain deleted code
- Binary files not supported
- AI explanations may occasionally misinterpret context
Love git-why? Check out our other developer CLI tools:
- roast-cli β AI code reviews with Gordon Ramsay energy. Brutally honest feedback from your terminal.
- portguard β Monitor and kill zombie processes hogging your ports. Fix
EADDRINUSEin one command. - oops β Pipe any error to AI for instant fixes. Debug faster with AI-powered error analysis.
π° Read the launch article on Dev.to: 4 CLI Tools Every Developer Needs (That You've Never Heard Of)
MIT
Built with Anthropic Claude, Commander.js, and Chalk.
Made by muin Β· Good code tells you what. Great code tells you why.