git why
HEAD · bccbabf2026-10-04Allison Coleman

Semantic archaeology for Git

The commit already tells you why.

git blame says who touched the line. Git Why finds the commit, in its author's own words, that explains it, even when you cannot name a single word in it.

$git why "why did the first release fail to publish to npm"
ceb07412026-10-03Allison Coleman

ci(release): fix tarball step and make post-publish jobs re-runnable (#17)

The v0.1.1 run published to npm, then failed packing the tarball because the pack destination did not exist, which skipped the GitHub release, MCP registry and Homebrew jobs.

.github/workflows/release.yml

     on:
       push:
         tags: ['v*']
+  # Re-run the post-publish jobs (GitHub release, MCP registry, Homebrew) for a
+  # tag whose npm publish already succeeded.
+  workflow_dispatch:
+    inputs:
+      tag:
+        description: 'Existing tag, e.g. v0.1.2'
Real output from git why 0.2.0 run on this repository. The question shares no vocabulary with the commit that answers it.

Getting startedHow it worksSource

05a2b3f2026-09-09alliecatowo

Dig through time, not just text

--first, --last and --removed resolve an endpoint from the lineage table. --timeline lays a subject out as it changed. --owners ranks who established an area by how relevant their commits are, not by surviving lines.

$ git why "the MCP bridge" --timeline -n 1 | cut -c1-88 | head -16

loading recording…

A real recorded session. Timings are actual latency.

$ git why "daemon" --owners -n 20 | cut -c1-88 | head -10

loading recording…

A real recorded session. Timings are actual latency.

76b84ff2026-10-03Allison Coleman

Hand the shovel to an agent

git why mcp serves two tools over stdio, git_why_search and git_why_status. It is a thin bridge onto the CLI's JSON contract, so an agent and a human cannot disagree about what a search returns.

claude mcp add git-why -- npx -y @alliecatowo/git-why mcp

Config for OpenCode, the Claude Code plugins and any other MCP client is in Agents & MCP.

c86a6f02026-09-10alliecatowo

Optional, and never the reason a search fails

A daemon keeps the index and model warm for roughly twice the speed. If it is missing, stale or dead, the query simply runs directly. Loopback only, bearer token, read-only.

$ git why server on / status / off

loading recording…

A real recorded session. Timings are actual latency.

b204ace2026-09-11alliecatowo

Measured, and wrong most of the time

Every number below is written into this page by bench/report.mjs from raw run data, and CI fails if it drifts. Full methodology, dataset provenance and the negative results are in the benchmark report.

174 recall questions — you remember a problem but cannot name anything in the commit that fixed it — derived mechanically from 6 pinned real repositories (curl, redis, requests, ripgrep, caddy, zod). Every question is verified unanswerable by keyword search before it enters the set: if git log --grep or git log -S finds the answer from the question's own words, the case is discarded.

strategyHit@1Hit@5MRRreturned nothing
git why0.2010.3740.2660
zg (semantic code search)0.0170.0400.0262
git log -G0.0060.0170.01115
git log --grep0.0000.0110.0030
git log --grep --all-match0.0000.0000.000109
git log -S0.0000.0000.00015

10.2x zg and 23x the best Git-native strategy — and the only approach that answers nearly every question rather than returning an empty set.

When you can name the symbol, use pickaxe search instead. On cross-file causal questions, git log -S scores Hit@10 0.950 against git why's 0.350. Semantic search has no advantage over a tool you can hand the exact literal.

That boundary is in the skill shipped with the plugin, because a tool that oversells itself makes an agent worse at its job.

Does it help an agent? ​

Retrieval quality is not the product. The question is whether an agent answering a real question does it more accurately, or in fewer turns, with the tool than without. Four arms over the same frozen tasks, paired per task, with token counts reconciled against the provider's own accounting database.

modelpaired naccuracy W-Lmedian tool calls saved
gemini-3.1-flash-lite61-22.5
claude-haiku-4-591-11
claude-sonnet-580-01
deepseek-v4-flash80-03.5
gemini-2.5-flash-lite62-11
gemini-3.1-flash-lite72-01
gemini-3.5-flash60-00.5 more

Results are mixed across models. At single-digit paired n per model this is descriptive, not significant, and it is reported that way deliberately — the direction is consistent, the magnitude is not established. Full method and per-arm figures in the benchmark report.

Method, per-arm figures and the registered hypothesis are in the benchmark report.

measurementresult
Index across 6 real repos (56,781 commits)5.51–7.84 KB/record
curl-curl (30,000 commits, 182,772 records)1.37 GiB, 7.84 KB/record
Query on curl-curl (30,000 commits) with git why server on384 ms p50, 491 ms p95
The same query with no daemon851 ms p50, 1371 ms p95
Diff/evidence ingestion, real-repo ablationearns its cost, ΔHit@5 +0.375

It is also wrong most of the time. Hit@5 of 0.374 means the right commit is outside the top five on 62.6% of these questions. It beats every alternative on them and still fails on most. Treat a result as a lead to verify with git show, never as established fact.

When to use ordinary Git instead ​

Git Why is ranked retrieval over a semantic index. That's the wrong tool for some jobs, and Git already has the right one:

  • A known exact string — git log -S / git log -G are exhaustive; a ranked keyword search is not.
  • An exhaustive search — ripgrep over a checkout, or git grep.
  • Verifying causality — similarity is not a timeline. Confirm ancestry with git merge-base, git log --ancestry-path, git show.

Read the full case in How it works.

v0.2.0 · 855b3732026-10-04Allison Coleman

Start digging

Node 22.12 or newer, macOS or Linux, any Git repository. The first query builds the index.

curl -fsSL https://alliecatowo.github.io/git-why/install.sh | sh
cd your-repo
git why "why do we retry on a 429 here?"

Getting startedCLI referenceFAQ and limits