Git Why

io.github.alliecatowov0.1.1更新於 Oct 3, 2026

Finds the Git commits that explain why code is the way it is: semantic and full-text history search.

已驗證STDIO僅桌面Developer ToolsKnowledge & Memory

概覽

AI 產生的概覽

讓助理對 Git 歷史進行語意與關鍵字搜尋,找出解釋程式碼為何如此的提交。

功能
Git Why 為倉庫的提交歷史建立索引,並回答關於它的自然語言問題,回傳符合的提交、作者本人的提交訊息以及相關 diff。它把語意索引與一般關鍵字索引結合,因此即使措辭與提交不同,也能比對你記得的问题。它只檢索證據,不自行生成解釋;選用守護程序會在查詢之間保持索引與模型常駐。
適用情境
當你記得出了什麼問題或發生了什麼變化,但記不住確切的術語、符號或提交訊息,並想找到解釋它的歷史時,它很有用。專案本身說明:當你能說出確切的字串或符號、需要窮盡式搜尋,或需要驗證因果關係時,應改用一般 Git。
執行需求
以 stdio 程序在本機執行,通常透過 npx 從 npm 套件 @alliecatowo/git-why 啟動,或全域安裝後由 Git 以子命令 git why 呼叫。需要 Node.js 22.12 或更新版本。未宣告任何驗證、環境變數或標頭。它讀取本機 Git 倉庫並在磁碟上建立索引。
安裝前請注意
它會讀取倉庫歷史並把索引資料寫入磁碟,選用守護程序會在查詢之間保持索引與嵌入模型常駐。結果是排序檢索而非證據:README 說明在其基準問題中有 62.6% 的情況下正確提交不在前五名,因此應把結果當作線索並用 git show 核實。提交訊息是作者的陳述,並非經過驗證的意圖。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Git Why,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

Git Why

[License: Apache-2.0] [Node.js >= 22.12] [CI]

git blame tells you who changed the code. git why finds the history that explains it.

Local-first semantic + full-text search over Git history. It returns the actual commit, its author's real words, and the relevant diff. It retrieves evidence; it does not generate an explanation of its own.

Real output from mise run demo, which rebuilds a small fixture repository from bench/fixtures/demo/build.mjs and runs these two queries against it. Nothing here is hand-written, and you can reproduce it in one command.

For output against real repositories — curl, zod, redis — including a worked case where this is the wrong tool, see docs/examples.md or the recorded terminal sessions.

text
$ git why "that bizarre bug where reconnecting subscribed twice"
1. 7deab42  Stop duplicate subscriptions after reconnect   2025-11-20 · Maya Chen
   Reconnecting re-ran the subscribe handler without clearing the previous   registration, so every reconnect doubled the delivered events.
   src/net/socket.ts   -export function connect(url) { return new Socket(url); }   +export function connect(url) {   +  const s = new Socket(url);   +  s.on('reconnect', () => resubscribeOnce(s));   +  return s;   +}
text
$ git why "why do we keep the session when the refresh token is empty?"
1. f17db20  Fix infinite token-refresh loop   2025-11-03 · Maya Chen
   Provider X can return an empty refresh token while the current access   token remains valid. Retrying here puts clients into an infinite loop.
   src/auth/refresh.ts    export function refresh(session, refreshToken) {   -  if (!refreshToken) throw new InvalidTokenError();   +  if (!refreshToken) return session;      return exchange(refreshToken);    }

Install

Install from npm (Node >= 22.12):

sh
npm install -g @alliecatowo/git-why

Or with Homebrew (macOS and Linux; pulls in node):

sh
brew install alliecatowo/tap/git-why

Or build from source:

sh
git clone https://github.com/alliecatowo/git-why.gitcd git-whynpm cinpm run buildnpm install -g .

The package installs a git-why executable, which Git dispatches as the subcommand git why. No alias setup needed. More install paths — pinned versions, a GitHub release tarball, building from source, uninstalling — are in docs/install.md.

Use it with an agent

Two plugins ship in plugins/:

pluginwhat you get
git-whyThe MCP server, a routing skill, and an index-management skill.
git-why-fullThe same, plus zg for current-code search and a history-explorer agent for questions that need several searches.

OpenCode users get opencode/ — an opencode.json with the MCP registration and an AGENTS.md fragment.

What the skill actually teaches is when not to reach for history. It tells an agent to use git log -S when it can name the symbol, because that is a case this tool measurably loses (Hit@10 0.950 against 0.350), and to use code search rather than history for the current state of the code. A skill that claims its own tool is always best makes an agent worse at its job.

Any other MCP client can run the server directly: npx -y @alliecatowo/git-why mcp (or git why mcp once installed). It is also listed in the MCP registry as io.github.alliecatowo/git-why.

See docs/plugin.md.

Make it faster (optional)

sh
git why server on

Holds the index, the embedding model and the lineage table open between queries. On curl — 30,000 commits — that is 569 ms a query down to 286 ms. Searches use it automatically once it is running.

It can never be the reason a search fails: if no daemon is running, or it is unreachable, or your index moved under it, the query runs directly instead. --daemon=direct opts out, --daemon=server requires one. See docs/daemon.md.

Why

git log --grep only matches words you already know. The reason code changed usually lives in a commit message, but you rarely remember its exact wording — you remember the problem, in your own words, months later.

Look again at the first example above: the query is "reconnecting subscribed twice" and the commit is titled "Stop duplicate subscriptions after reconnect." They share almost no vocabulary. That's not a coincidence Git Why is showing off — it's the actual point of a semantic index. It carries the meaning of the change, not just its words, alongside an ordinary keyword index for when you do know the exact term.

Git Why retrieves historical evidence: the commit, the author's actual words, and the relevant diff. Historical commit messages are assertions by their authors, not infallible accounts of intent, and some reasons were never committed at all — Git Why will not manufacture those.

Measured, not claimed

Every number below is written into this file by bench/report.mjs from raw run data, and CI fails if it drifts — no figure here was typed by hand. Full methodology, limits, and the negative results are in docs/report.md.

Against the tools you would otherwise use

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.

Where it loses

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 the honest positioning, and the shipped skill tells agents both halves:

  • cannot name the term → git why
  • can name the term → git log -S
  • current code, not history → zg

Scale and cost

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: docs/report.md.

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

What works, and what does not

Eight optimisations were implemented and measured. One survived.

The one that did: lexical overlap between the question and the commit's own message, reranked over a candidate pool deeper than the result list. Weight chosen on a dev half, evaluated once on the held-out half — +26% MRR and +44% Hit@1 on cases it never saw. Shipped.

The seven that did not: a prose-tuned embedding model, pseudo-relevance feedback, a prose-commit penalty, caller-side query restatement, wider result windows, structural expansion, and phrase fusion. None improved MRR.

What made the difference was not a better idea but a different question. The seven all asked "does this rank better". The one that worked started by asking where the right commit actually is — and found that a quarter of the corpus is retrieved but ranked below 5, which is a reordering problem, while 42% is never retrieved at all, which is not. See docs/decisions.md.

The remaining headroom is that 42%: a recall problem in the embedding itself. That is now measured rather than guessed — docs/embedding.md compares ten models on a fixed pool. Transformer embedders score +41% (jina-v2-small) and +64% (jina-v2-base) MRR over the shipped static one, at 191x and 1287x the indexing time plus an ONNX runtime. Both are available opt-in; the default stays fast and dependency-free, because a tool that installs in seconds and indexes in under a minute should not quietly become one that needs fifteen hours.

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 and git log -G are exhaustive. Keyword mode here is ranked, not exhaustive.
  • 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 and git show.

Git Why is for the case where you remember what happened but not what it was called.

Learn more

  • Documentation site — guided install, how retrieval works, CLI reference, FAQ.
  • ROADMAP.md — pull requests, gh why, wikis, and what would need measuring before any of it ships.
  • docs/embedding.md — nine embedding models measured, the +41% one you can opt into, and why the default did not change.
  • docs/daemon.md — the optional daemon: what it holds warm, why it can never break a search, and its security posture.
  • docs/indexes.md — where indexes live, worktrees, submodules, monorepos, disk use, and the shared model cache.
  • docs/examples.md — real output on real repositories, including a case where this is the wrong tool.
  • docs/plugin.md — both plugins, the MCP tools, the skills, and why there is no hook.
  • docs/decisions.md — what was tried and rejected, with the measurements. Seven optimisations that did not work.
  • docs/install.md — every install path and uninstall, including where the index and model cache live on disk.
  • docs/operations.md — the full operational contract: durability, concurrency, exit codes, history scope, coverage limits.
  • docs/report.md — the benchmark report this README's numbers come from.
  • docs/spec.md — the build specification this was written against. Source comments cite its sections, so it is kept as provenance rather than as user documentation.

Development

sh
mise setup             # install dependencies, then doctormise check             # format, lint, typecheck, protocol hash, unit testsmise test:integration  # real repositories, real storage, real locksmise test:package      # pack, install into a clean prefix, invoke through Gitmise site:build        # build the docs/marketing site in site/mise tasks             # everything else, including every benchmark

Numbers in README.md, site/index.md and docs/report.md are written by bench/report.mjs from raw run data — CI fails if you edit one by hand. The man page, the site's CLI reference and all three shell completions are checked against git why -h, which is the only place the flag set is defined.

See docs/contributing.md for module ownership and how to cut a release.

License

Apache-2.0. See LICENSE and NOTICE.

來源:README.md,提交 1d3ee71

工具

0
工具後設資料尚未被收錄。

版本歷史

1
  1. v0.1.1最新Oct 3, 2026