关于 Git Why
Git Why 是面向开发者和编码 Agent 的本地优先 Git 历史搜索工具,可按问题语义和全文查找相关提交。它返回提交、作者原文和相关差异作为证据,而不自行生成原因解释。
主要功能
- 01语义与全文搜索 Git 历史
- 02展示提交、作者原文和差异
- 03增量建立仓库索引
- 04提供可选常驻索引服务
- 05支持 MCP 与 Agent 插件
适用场景
- 01记得问题但想不起提交关键词时查找历史
- 02查看某项代码改动的提交证据
- 03将历史检索接入 Agent 工作流
MCP 相关
它提供 MCP 服务,可由 `npx -y @alliecatowo/git-why mcp` 启动,向 MCP 客户端提供 Git 历史检索。项目还提供包含该服务的 Agent 插件。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
2收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| cwd | string | 否 | 仓库目录。默认为服务器进程目录。 |
| mode | enum | 否 | hybrid | text | semantic |
| sort | enum | 否 | relevance | oldest | newest |
| limit | number | 否 | |
| query | string | 是 | 用自然语言表述的问题。例如:“为什么放弃前要重试两次?”、“那个重复发送 webhook 的 bug 是怎么回事?”描述症状或决策,而不是文件——`git log -- <path>` 已能搜索文件,而且效果更好。 |
| groups | array | 否 | 按提交级 RRF 融合的其他查询组。 |
| owners | boolean | 否 | 同时返回建立此领域的人员,按其提交的相关性排序,而非按仍存留的代码行数(git blame)或提交次数(git shortlog)排序。适用于“谁构建了这个”、“谁应该审核这个”、“谁了解这个”等问题。 |
| temporal | object | 否 | 可选的时间检索约束。省略时由 CLI 执行查询拆解。 |
| temporal.type | enum | 否 | first | last | removed | changed_when | before | after | between | around | timeline |
| temporal.anchor | string | 否 | |
| temporal.anchorEnd | string | 否 |
详细介绍
Git Why
git blame 会告诉你是谁修改了代码。git why 会找出能解释这些修改的历史记录。
在 Git 历史记录中进行本地优先的语义搜索和全文搜索。它会返回实际提交、作者的原话,以及相关差异。它检索证据,不会自行生成解释。
以下是 mise run demo 的实际输出。该命令会根据 bench/fixtures/demo/build.mjs 重建一个小型示例仓库,并对其运行以下两个查询。这里的内容并非手工编写,你可以用一条命令重现。
如需查看真实仓库(curl、zod、redis)的输出,以及一个说明何时不该使用此工具的案例,请参阅docs/examples.md或录制的终端会话。
$ 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;
+}
$ 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);
}
安装
从 npm 安装(Node >= 22.12):
npm install -g @alliecatowo/git-why
或使用 Homebrew 安装(macOS 和 Linux;会一并安装 node):
brew install alliecatowo/tap/git-why
或从源代码构建:
git clone https://github.com/alliecatowo/git-why.git
cd git-why
npm ci
npm run build
npm install -g .
该软件包会安装一个 git-why 可执行文件,Git 会将其作为子命令 git why 调用。无需设置别名。更多安装方式——指定固定版本、使用 GitHub 发布版 tarball、从源代码构建、卸载——请参阅docs/install.md。
首次运行
cd your-repo
git why "why do we retry twice before giving up"
首次查询会下载一个小型嵌入模型(约 32 MB,已验证校验和,缓存于 ~/.cache/git-why/models),并将仓库的历史记录索引到 .git/why/ 中;之后的查询会增量执行。如果你使用代理或处于离线状态,请参阅docs/operations.md中的 HTTPS_PROXY、GIT_WHY_MODEL_BASE_URL(镜像)和 GIT_WHY_OFFLINE。运行 git why status 可查看索引是否为最新。
与 Agent 搭配使用
plugins/ 中提供了两个插件:
| 插件 | 功能 |
|---|---|
git-why | MCP 服务、路由技能和索引管理技能。 |
git-why-full | 同上,另含用于搜索当前代码的 zg,以及一个用于处理需要多次搜索的问题的历史探索 Agent。 |
OpenCode 用户可使用 opencode/,其中包含带有 MCP 注册信息的 opencode.json 和一段 AGENTS.md 配置。
该技能实际教会 Agent 的是何时不该查阅历史记录。如果能说出符号名称,它会告诉 Agent 使用 git log -S,因为在这种情况下,该工具的表现明显较差(Hit@10 为 0.950,而它为 0.350);对于代码的当前状态,则应使用代码搜索,而不是查阅历史记录。声称自身工具总是最佳选择的技能,只会让 Agent 更难胜任工作。
其他任何 MCP 客户端都可以直接运行该服务:npx -y @alliecatowo/git-why mcp(安装后也可以运行 git why mcp)。它也已作为 io.github.alliecatowo/git-why 收录于 MCP 注册表。
请参阅docs/plugin.md。
提升速度(可选)
git why server on
该守护进程会在多次查询之间保持索引、嵌入模型和血缘表处于打开状态。在包含 30,000 次提交的 curl 仓库中,每次查询耗时可从 569 ms 降至 286 ms。守护进程运行后,搜索会自动使用它。
搜索绝不会因守护进程而失败:如果守护进程未运行、无法访问,或索引在其运行期间被移动,查询就会改为直接运行。--daemon=direct 可选择不使用守护进程,--daemon=server 则要求守护进程正在运行。请参阅docs/daemon.md。
原因
git log --grep 只能匹配你已经知道的词。代码改动的原因通常写在提交消息中,但你很少记得它的确切措辞——几个月后,你记得的是自己话语中的那个_问题_。
再看看上面的第一个示例:查询是“reconnecting subscribed twice”,提交标题是“Stop duplicate subscriptions after reconnect”。两者几乎没有共同词汇。这并非 Git Why 在炫技——这正是语义索引的意义所在。它会保留改动的含义,而不只是词语;同时也提供普通关键词索引,以便你_确实_知道确切术语时使用。
Git Why 会检索历史证据:提交、作者的原话,以及相关差异。历史提交消息是作者作出的陈述,并非对意图的绝对可靠记录;有些原因甚至从未提交过——Git Why 不会凭空捏造这些内容。
经测量,而非凭空声称
以下每个数字都由 bench/report.mjs 根据原始运行数据写入此文件,CI 会在数据变化时失败——这里没有任何数字是手动输入的。完整的方法、局限性和负面结果见
docs/report.md。
与其他可用工具的对比
174 个召回问题——你记得某个问题,却说不出修复它的提交中的任何内容——通过对 6 个固定版本的真实仓库(curl、redis、requests、ripgrep、caddy、zod)进行机械化推导得出。每个问题在纳入集合前都会经过验证,确保无法通过关键词搜索回答:如果 git log --grep 或 git log -S 能从问题本身的词语中找到答案,该案例就会被丢弃。
| 策略 | Hit@1 | Hit@5 | MRR | 无结果 |
|---|---|---|---|---|
| git why | 0.201 | 0.374 | 0.266 | 0 |
| zg(语义代码搜索) | 0.017 | 0.040 | 0.026 | 2 |
| git log -G | 0.006 | 0.017 | 0.011 | 15 |
| git log --grep | 0.000 | 0.011 | 0.003 | 0 |
| git log --grep --all-match | 0.000 | 0.000 | 0.000 | 109 |
| git log -S | 0.000 | 0.000 | 0.000 | 15 |
比 zg 高 10.2 倍,比最佳 Git 原生策略高 23 倍——而且这是唯一一种几乎能回答所有问题,而不是返回空结果集的方法。
表现较差的场景
如果你能说出符号名称,就改用 pickaxe 搜索。对于跨文件因果问题,git log -S 的 Hit@10 得分为 0.950,而 git why 为 0.350。对于你能提供确切字面内容的工具,语义搜索并无优势。
这就是诚实的适用范围,已发布的 技能会告诉 Agent 这两个方面:
- 说不出术语 →
git why - 说得出术语 →
git log -S - 查当前代码,而非历史 →
zg
规模与成本
它能帮助 Agent 吗?
检索质量不是产品本身。关键在于:Agent 回答真实问题时,借助工具是否能答得更准确,或减少交互轮数。针对同一组冻结任务设置了四组实验,每项任务均进行配对,并根据提供方自己的计量数据库核对 token 数量。
| 模型 | 配对样本数 | 准确率胜-负 | 节省的工具调用中位数 |
|---|---|---|---|
| gemini-3.1-flash-lite | 6 | 1-2 | 2.5 |
| claude-haiku-4-5 | 9 | 1-1 | 1 |
| claude-sonnet-5 | 8 | 0-0 | 1 |
| deepseek-v4-flash | 8 | 0-0 | 3.5 |
| gemini-2.5-flash-lite | 6 | 2-1 | 1 |
| gemini-3.1-flash-lite | 7 | 2-0 | 1 |
| gemini-3.5-flash | 6 | 0-0 | 多 0.5 |
不同模型的结果不一。每个模型的配对样本数都只有个位数,因此这些结果仅作描述,不具统计显著性;我们有意如实报告这一点——趋势一致,但效果幅度尚未确定。完整方法和各组数据见基准测试报告。
方法、各组数据和预注册假设:docs/report.md。
| 测量项 | 结果 |
|---|---|
| 6 个真实代码库的索引(56,781 次提交) | 5.51–7.84 KB/条记录 |
| curl-curl(30,000 次提交,182,772 条记录) | 1.37 GiB,7.84 KB/条记录 |
在 curl-curl(30,000 次提交)上执行查询 git why server on | 384 ms p50,491 ms p95 |
| 无守护进程时执行相同查询 | 851 ms p50,1371 ms p95 |
| 差异/证据摄取,真实代码库消融测试 | 值得投入,ΔHit@5 +0.375 |
哪些有效,哪些无效
共实现并测量了八项优化,只有一项通过验证。
有效的那一项:计算问题与提交自身说明之间的词汇重叠度,并在比结果列表更深的候选池中重新排序。权重在开发集的一半上选定,再在留出的一半上评估一次——在从未见过的样本上,MRR 提升了 26%,Hit@1 提升了 44%。已发布。
其余七项均无效:针对散文调优的嵌入模型、伪相关反馈、散文式提交惩罚、调用方重述查询、扩大结果窗口、结构扩展和短语融合。它们都没有改善 MRR。
起作用的不是更好的想法,而是换了一个问题。那七项都在问“这样排序是否更好”。有效的那项则先问:正确的提交究竟在哪里?结果发现,语料库中有四分之一已被检索到,但排名低于第 5 位,这是重排问题;而有 42% 根本没有被检索到,这并非重排问题。详见
docs/decisions.md。
剩余的提升空间就在这 42% 上:这是嵌入模型本身的召回率问题。现在我们测量了它,而不再凭空猜测——
docs/embedding.md 在固定候选池上比较了十种模型。Transformer 嵌入模型的 MRR 分别比已发布的静态模型高 41%(jina-v2-small)和 64%(jina-v2-base),但索引耗时分别是其 191 倍和 1287 倍,还需要 ONNX 运行时。两者均可选择启用;默认方案仍保持快速且无依赖,因为一个只需几秒即可安装、不到一分钟即可完成索引的工具,不应悄然变成一个需要十五小时才能完成索引的工具。
而且它大多数时候都是错的。 Hit@5 为 0.374,意味着对于这些问题,62.6% 的情况下正确提交不在前五名之内。尽管在这些问题上它仍胜过所有其他方案,但大多数时候还是会失败。应将结果视为有待通过 git show 核实的线索,绝不要当作已证实的事实。
何时改用普通 Git
Git Why 是基于语义索引进行排序检索的工具。有些任务不适合用它,而 Git 已经提供了合适的工具:
- 已知的确切字符串。
git log -S和git log -G会穷尽所有结果。这里的关键词模式采用排序,而非穷尽搜索。 - 穷尽搜索。 在检出目录中使用
ripgrep,或使用git grep。 - 验证因果关系。 相似度不等于时间线。使用
git merge-base、git log --ancestry-path和git show确认提交的祖先关系。
当你记得发生过什么,却不记得它叫什么时,就适合使用 Git Why。
了解更多
- 文档网站 — 安装指南、检索原理、CLI 参考和常见问题解答。
ROADMAP.md— 拉取请求、gh why、wiki,以及这些功能发布前需要进行哪些衡量。docs/embedding.md— 对 9 种嵌入模型的测评、可选启用且效果提升 41% 的模型,以及默认模型为何没有改变。docs/daemon.md— 可选守护进程:它会预热哪些内容、为何绝不会导致搜索失败,以及其安全状况。docs/indexes.md— 索引的存放位置、工作树、子模块、单体仓库、磁盘占用和共享模型缓存。docs/examples.md— 在真实仓库中的实际输出,包括一个不适合使用此工具的案例。docs/plugin.md— 两个插件、MCP 工具、技能,以及为何没有钩子。docs/decisions.md— 尝试过但最终放弃的方案及相关测量数据。7 项未能奏效的优化。docs/install.md— 所有安装和卸载方式,包括索引和模型缓存在磁盘上的存放位置。docs/operations.md— 完整的运行约定:持久性、并发、退出码、历史范围和覆盖范围限制。docs/report.md— 本 README 中数据所依据的基准测试报告。docs/spec.md— 本项目编写时遵循的构建规范。源码注释会引用其中的章节,因此该文档作为出处保留,而非用户文档。
开发
mise setup # install dependencies, then doctor
mise check # format, lint, typecheck, protocol hash, unit tests
mise test:integration # real repositories, real storage, real locks
mise test:package # pack, install into a clean prefix, invoke through Git
mise site:build # build the docs/marketing site in site/
mise tasks # everything else, including every benchmark
README.md、site/index.md 和 docs/report.md 中的数据由 bench/report.mjs 根据原始运行数据生成——如果手动编辑,CI 就会失败。手册页、网站的 CLI 参考以及全部 3 种 Shell 补全都会根据 git why -h 进行检查;标志集仅在此处定义。
有关模块职责归属和如何发布版本,请参阅 docs/contributing.md。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。