git棱镜
为LLM代理优化了git数据。五种替代以人为本的MCP工具 与结构化JSON的区别——函数级粒度、导入跟踪、, 依赖关系更改、完整文件快照、每次提交历史记录、函数 上下文(调用者、被调用者、测试引用)和一个调用 review_change 结合清单和功能上下文进行公关审查的编排。
问题
Git的瓷器输出(diff, log, --stat)是为人眼设计的。当 LLM代理解析统一的diff,并在其上燃烧令牌 @@ 大块头, +/- 例如文本、行前缀和没有语义意义的空白上下文。更糟糕的是 必须重建 _到底发生了什么变化_ --修改了哪些功能,哪些 无论文件是从原始文本生成的,都添加了导入。
git prism直接为代理提供结构化数据:每个文件的变更清单 元数据和功能级别分析,以及完整的前后文件内容 需要更深入的检查。
安装
来自crates.io(推荐)
cargo install git-prism来源
cargo install --path .二进制下载
从中获取预构建的二进制文件 页面。
Homebrew(macOS和Linux)
brew tap mikelane/tap
brew install git-prismMCP注册
将git prism注册为Claude Code的MCP服务器:
claude mcp add git-prism -- git-prism serve就是这样。服务器使用stdio传输,在所有克劳德代码中都可用 会议。
捆绑重定向挂钩
它做什么
捆绑的重定向挂钩可以阻止意外的bash重定向,这些重定向会覆盖代理会话中的跟踪文件。它在监视列表中的路径和硬块上发出软警告 gh pr diff 和 mcp__github__* 使用输出重定向的工具调用。钩子使用Python stdlib标记器(shlex)从结构上解析bash,捕获复合命令(&&)、子壳、管道和变量扩展——而不仅仅是简单的正则表达式。
需要 python3 (3.9+)在PATH上。macOS提供此功能;Linux用户可以通过系统包管理器进行安装。
安装
git-prism hooks install命令复制 ~/.claude/hooks/git-prism-redirect.sh 旁边的Python助手,然后写一个 PreToolUse 挂钩进入克劳德代码 ~/.claude/settings.json。默认范围为 user 因为克劳德代码问题 人类学/克劳德编码#13898 阻止自定义子代理正确调用项目范围的MCP服务器——使用用户范围确保重定向在根代理和子代理中都有效。
卸载和状态
git-prism hooks uninstall # removes the hook file and settings.json entry
git-prism hooks status # shows whether the hook is installed and at which scope工具
get_change_manifest
返回关于两个git ref之间变化的结构化元数据。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
base_ref | 字符串 | _(必填)_ | 基本git ref(提交SHA、分支、标签, HEAD~1) |
head_ref | 字符串 | _(省略→ 工作树)_ | 当请求中省略该字段时,该工具会进行比较 base_ref 针对工作树(阶段性+非阶段性更改),而不是区分两个提交。经过 "HEAD" 显式生成一个提交模式差异 HEAD,这与工作树模式不同。 |
repo_path | string | cwd | git存储库的路径 |
include_patterns | string\[\] | [] | 要包括的球状图案(例如。 ["*.rs", "*.go"]) |
exclude_patterns | string\[\] | [] | 要排除的球状图案(例如。 ["*.lock"]) |
include_function_analysis bool的。 false | 启用树保姆功能/导入分析(选择加入;默认保持响应紧凑) | ||
cursor | 字符串 | null | 来自先前响应的不透明分页光标 |
page_size | int | 100 | 每页最大文件条目数(1-500) |
输出示例:
{
"metadata": {
"repo_path": "/home/user/myproject",
"base_ref": "main",
"head_ref": "HEAD",
"base_sha": "a1b2c3d4e5f6",
"head_sha": "f6e5d4c3b2a1",
"generated_at": "2026-04-03T12:00:00Z",
"version": "x.y.z"
},
"summary": {
"total_files_changed": 3,
"files_added": 1,
"files_modified": 2,
"files_deleted": 0,
"files_renamed": 0,
"total_lines_added": 47,
"total_lines_removed": 12,
"total_functions_changed": 4,
"languages_affected": ["go", "rust"]
},
"files": [
{
"path": "src/handler.go",
"old_path": null,
"change_type": "modified",
"change_scope": "committed",
"language": "go",
"is_binary": false,
"is_generated": false,
"lines_added": 25,
"lines_removed": 8,
"size_before": 1200,
"size_after": 1450,
"functions_changed": [
{
"name": "HandleRequest",
"old_name": null,
"change_type": "signature_changed",
"start_line": 15,
"end_line": 42,
"signature": "func HandleRequest(ctx context.Context, req *Request) (*Response, error)"
},
{
"name": "validateInput",
"old_name": "checkInput",
"change_type": "renamed",
"start_line": 44,
"end_line": 58,
"signature": "func validateInput(req *Request) error"
}
],
"imports_changed": {
"added": ["context", "errors"],
"removed": ["log"]
}
}
],
"dependency_changes": [
{
"file": "go.mod",
"added": [{"name": "github.com/pkg/errors", "old_version": null, "new_version": "v0.9.1"}],
"removed": [],
"changed": []
}
],
"pagination": {
"total_items": 3,
"page_start": 0,
"page_size": 100,
"next_cursor": null
}
}get_file_snapshots
在两个git ref处返回文件内容之前/之后的完整值。没有要解析的差异-- 代理在每个时间点都会获得完整的文件。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
base_ref | 字符串 | _(必填)_ | 基本git参考 |
head_ref | 字符串 | "HEAD" | 头部git ref |
paths | string\[\] | _(必填)_ | 快照的文件路径(最多20个) |
repo_path | string | cwd | git存储库的路径 |
include_before bool的。 true | 在基引用中包含文件内容 | ||
include_after bool的。 true | 在head ref处包含文件内容 | ||
max_file_size_bytes | int | 100000 | 截断大于此值的文件 |
line_range | \[int,int\] | null | 仅返回此范围内的行(1-索引) |
include_diff_hunks bool的。 false | 包括大块边界以进行差异相对线映射 |
输出示例:
{
"metadata": {
"repo_path": "/home/user/myproject",
"base_ref": "main",
"head_ref": "HEAD",
"generated_at": "2026-04-03T12:00:00Z"
},
"files": [
{
"path": "src/handler.go",
"language": "go",
"is_binary": false,
"before": {
"content": "package main\n\nfunc HandleRequest(req *Request) error {\n // old implementation\n}\n",
"line_count": 5,
"size_bytes": 82,
"truncated": false
},
"after": {
"content": "package main\n\nimport \"context\"\n\nfunc HandleRequest(ctx context.Context, req *Request) (*Response, error) {\n // new implementation\n}\n",
"line_count": 7,
"size_bytes": 130,
"truncated": false
},
"error": null
}
],
"token_estimate": 53
}get_commit_history
在一个范围内的每个提交返回一个清单,以便代理可以看到在 每个提交都是单独的,而不是一个折叠的差异。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
base_ref | 字符串 | _(必填)_ | 基本git ref(独占-在此之后提交) |
head_ref | 字符串 | _(必填)_ | 头部git ref(含) |
repo_path | string | cwd | git存储库的路径 |
cursor | 字符串 | null | 来自先前响应的不透明分页光标 |
page_size | int | 100 | 每页最大提交次数(1-500) |
输出示例:
{
"commits": [
{
"metadata": {
"sha": "a1b2c3d4",
"message": "add validation helper",
"author": "Jane Dev",
"timestamp": "2026-04-03T10:30:00+00:00"
},
"files": [
{
"path": "src/validate.rs",
"change_type": "added",
"language": "rust",
"lines_added": 25,
"lines_removed": 0
}
],
"summary": {
"total_files_changed": 1,
"files_added": 1,
"total_lines_added": 25,
"total_lines_removed": 0
}
}
],
"pagination": {
"total_items": 1,
"page_start": 0,
"page_size": 100,
"next_cursor": null
}
}get_function_context
返回每个已更改函数的调用者、被调用者和测试引用 在两个裁判之间。回答“这个函数叫什么?”和“这个函数是什么?” 功能调用?“代理人不必grep。
使用Rust、Python、Go和Types/JavaScript的导入感知作用域 将调用者扫描筛选为实际导入更改模块的文件。这 消除了叶名冲突中的误报,并提高了 大型回购。不支持的语言会退回到完整的仓库扫描。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
base_ref | 字符串 | _(必填)_ | 基本git参考 |
head_ref | 字符串 | _(必填)_ | 头部git ref |
repo_path | string | cwd | git存储库的路径 |
cursor | 字符串 | null | 来自先前响应的不透明分页光标 |
page_size | int | 25 | 每页最大功能条目数(1-500)。默认值低于清单工具,因为每个条目都包含呼叫者/被呼叫者列表 |
function_names | string\[\] | null | 限制对具有这些名称的函数的响应。使用此选项重新查询其列表在先前调用中被夹紧的函数 |
max_response_tokens | int | 8192 | 以估计令牌为单位的响应大小预算。当超出时,呼叫者/被呼叫者列表将按条目进行修剪。 0 禁用预算 |
输出示例:
{
"metadata": {
"base_ref": "HEAD~1",
"head_ref": "HEAD",
"base_sha": "a1b2c3d4",
"head_sha": "f6e5d4c3",
"generated_at": "2026-04-09T12:00:00Z"
},
"functions": [
{
"name": "validate_input",
"file": "src/validation.rs",
"change_type": "modified",
"blast_radius": {
"production_callers": 1,
"test_callers": 1,
"has_tests": true,
"risk": "low"
},
"scoping_mode": "scoped",
"callers": [
{ "file": "src/handler.rs", "line": 42, "caller": "handle_request", "is_test": false }
],
"callees": [
{ "callee": "check_length", "line": 15 },
{ "callee": "check_format", "line": 18 }
],
"test_references": [
{ "file": "tests/test_validation.rs", "line": 10, "caller": "test_validate_empty", "is_test": true }
],
"caller_count": 2
}
]
}这 scoping_mode 字段指示如何执行呼叫者扫描: "scoped" 意味着使用了基于导入的筛选(更精确,但可能会错过以下呼叫者 使用不寻常的导入模式),同时 "fallback" 表示每 repo中的文件(权威但速度较慢)。使用此选项决定是否 零调用者结果是确定的或可能不完整的。
review_change
返回ref的组合更改清单和函数级爆炸半径 在一次通话中。使用这个 而不是 git diff .. 当 审查PR、审核重构或评估合并安全性——它会给出答案 在一次工具调用中“发生了什么变化,可能会发生什么中断”,具有结构化 JSON而不是原始的diff文本。
取代常见的两步工作流程(get_change_manifest 然后 get_function_context)使用一个同时在内部运行和拆分的调用 响应大小预算40/60(manifest/function_context)。
参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
base_ref | 字符串 | _(必填)_ | 基本git参考 |
head_ref | 字符串 | _(省略→ 工作树)_ | Head git ref省略以与工作树进行比较(仅清单;函数上下文的一半返回空,因为调用者/被调用者需要提交的内容) |
repo_path | string | cwd | git存储库的路径 |
include_patterns | string\[\] | [] | 球形图案包括 |
exclude_patterns | string\[\] | [] | 要排除的球形图案 |
function_names | string\[\] | null | 将函数上下文限制为这些名称的一半 |
max_response_tokens | int | 8192 | 合并预算;在manifest和function_context之间分割40/60。 0 禁用双方的预算 |
manifest_cursor | 字符串 | null | 不透明光标仅前进清单的一半 |
function_context_cursor | 字符串 | null | 不透明光标仅前进函数上下文的一半 |
page_size | int | 25 | 两半使用的页面大小 |
这两个游标是独立的,因此代理可以前进一半(例如,行走 通过一个长文件列表),而无需重新分页另一个。每个子响应 将其预算份额纳入 metadata.budget_tokens 所以下游 可观测性可以审计分裂决策。
输出示例:
{
"manifest": {
"metadata": {
"base_ref": "HEAD~1",
"head_ref": "HEAD",
"budget_tokens": 1638,
"...": "..."
},
"summary": { "total_files_changed": 3, "...": "..." },
"files": [{ "path": "src/lib.rs", "...": "..." }],
"pagination": { "next_cursor": null, "...": "..." }
},
"function_context": {
"metadata": {
"base_ref": "HEAD~1",
"head_ref": "HEAD",
"budget_tokens": 2458,
"...": "..."
},
"functions": [{ "name": "validate", "blast_radius": { "risk": "medium" }, "...": "..." }],
"pagination": { "next_cursor": null, "...": "..." }
}
}CLI使用情况
git prism还可以作为一个独立的CLI用于脚本编写和调试:
# Change manifest between two refs
git-prism manifest HEAD~1..HEAD
# Manifest for a specific repo path
git-prism manifest main..feature-branch --repo /path/to/repo
# Per-commit history for a range
git-prism history HEAD~5..HEAD
# Smaller pages for constrained environments
git-prism manifest main..HEAD --page-size 50
# File snapshots for specific paths
git-prism snapshot HEAD~3..HEAD --paths src/main.rs src/lib.rs
# Function context (callers, callees, test references)
git-prism context HEAD~1..HEAD
# List supported languages
git-prism languages这 manifest, snapshot, history,以及 context 命令将JSON输出到 stdout。这 manifest 和 history 命令内部自动分页(默认 页面大小500,可配置 --page-size)并始终返回完整 结果。这 languages 命令输出纯文本。
代理工作流
一个调用路径:PR审查和重构审计
对于公关审查、重构审计或任何“发生了什么变化,什么可能会破坏”的问题, 使用 review_change 而不是 git diff:
review_change(base_ref="main", head_ref="HEAD")这将返回一个组合 { manifest, function_context } 一次通话中的有效载荷,拆分 代币预算40/60介于两半之间。它取代了两步清单+ function_context工作流,当您在同一会话中需要两者时。
三条呼叫路径:有针对性的检查
当你需要更精细的控制时——每一半的预算不同,按函数名称过滤, 或者深入到特定文件中——按顺序使用各个工具:
第一步:与 get_change_manifest
询问清单以了解变化的形状。摘要告诉你 文件数、行数和受影响的语言。每个文件的条目告诉你 哪些函数更改了签名,添加了哪些导入,以及文件是否 生成(可以跳过)。
第二步:爆炸半径 get_function_context
对于步骤1中标识的更改的函数,请求函数上下文。这 告诉哪些其他文件调用了每个更改的函数,每个更改了什么 函数调用,以及哪些测试文件引用它。每个函数都包含一个 blast_radius 带有a的对象 risk 水平(none, low, medium, high) 根据生产呼叫者计数和测试覆盖率计算——按风险排序 首先查看影响最大的更改。代理人永远不必费力地通过 代码库,用于查找调用者或猜测要检查哪些测试。
第三步:深潜 get_file_snapshots
一旦您知道哪些文件和调用者很重要,请请求以下内容的完整快照 影响最大的文件。您在内容之前/之后完成-无需重建 来自diff-hunks的文件。使用 line_range 专注于特定的部分和 include_before: false 当你只需要当前状态时。通过 include_diff_hunks: true 为计算获得统一的差分块边界 diff相对行位置(例如,GitHub内联评论)。
这两条路径都保持了较低的令牌使用率。 review_change 是最有效的开始 大多数复习任务的分数;当你需要时,这三条呼叫路径是值得的 有针对性的重新查询或希望单独浏览大型清单 一个大的功能列表。
分页
get_change_manifest 和 get_commit_history 返回a pagination 对象打开 每个响应:
"pagination": {
"total_items": 842,
"page_start": 0,
"page_size": 100,
"next_cursor": "eyJvZmZzZXQiOjEwMCwiYmFzZV9zaGEiOiIuLi4ifQ=="
}当 next_cursor 非null,将其作为 cursor 参数在 下一次调用以获取下一页。游标是一个不透明的base64有效载荷 其对页面偏移量加上解析的基/头SHA进行编码;服务器 拒绝SHA不再与后续提供的参考匹配的光标 调用,因此光标是针对 main..feature 不能对某个对象重复使用 不同的范围。宣言 summary 始终反映中的所有文件 变更集,无论返回哪个页面,因此代理都可以从中进行分类 在决定是否翻阅剩余的文件条目之前,请先浏览第1页。
page_size 在服务器端被夹紧到 1..=500 范围;价值观之外 范围是强制的,而不是被拒绝的。CLI(git-prism manifest, git-prism history)内部分页,始终返回完整 结果;光标合约仅通过MCP工具界面可见。
支持的语言
功能级别分析使用 树保姆 从源代码中提取函数、方法、导入和调用站点。
| 语言 | 扩展名 | 摘录 |
|---|---|---|
C .c, .h | 函数、声明, #include 指令 | |
C .cpp, .hpp, .cc, .cxx, .hh, .hxx | 类/命名空间限定的方法、函数, extern "C" 阻碍, #include 指令 | |
C .cs | 方法、构造器, using 指令 | |
| 去吧 | .go | 函数、方法、导入 |
Java .java | 方法、构造函数、导入 | |
| JavaScript | .js, .jsx | 函数、导出函数、箭头函数、方法、导入 |
| Kotlin | .kt, .kts | 函数、方法、扩展函数、导入 |
| PHP | .php | 功能、方法, use 声明 |
python .py | 功能、装饰功能、方法、导入 | |
| 红宝石 | .rb | 方法、单例方法, require/require_relative |
| 生锈 | .rs | 函数、方法、use语句 |
| Swift | .swift | 函数、方法、init声明、导入 |
| TypeScript | .ts, .tsx | 函数、导出函数、箭头函数、方法、导入 |
不支持的语言的文件仍然显示在清单中 行/大小/更改类型元数据-- functions_changed 是 null (不是空的 数组)来区分“没有语法可用”和“已分析,没有更改”
内容感知功能存在差异
通过比较函数体的SHA-256哈希值来检测函数更改 内容,而不是行位置。这意味着:
- 重新排序的函数 (移动但未修改)不产生更改条目,
消除了浪费试剂注意的假阳性。
- 仅身体变化 (相同的签名,不同的实现)被检测到
作为 modified,即使行号没有移动。
- 重命名函数 当一个不匹配的添加函数共享一个
带有不匹配的已删除函数的体哈希。这些产生了一个单一 renamed 进入与 old_name 已填充,而不是单独 deleted + added.
这 change_type 函数的值为: added, modified, deleted, signature_changed, renamed。重命名的条目在中包含以前的名称 这 old_name 字段(所有其他变量为空),以便代理可以关联 将函数重命名回其历史记录。
空白和评论敏感性。 主体哈希值是在原始哈希值上计算的 树视图中函数体的字节跨度。重新格式化运行, 注释添加或删除、尾随空格更改和缩进 因此,shift将改变哈希值并产生 modified 即使在 可执行逻辑不变。未来的版本可能会规范空白 并在哈希之前删除评论;在此之前,在文件上运行格式化程序 将显示每个触摸的功能 modified 在下一次清单呼叫时。
依赖文件跟踪
git prism解析添加、删除和版本更改的依赖文件和报告 包装:
Cargo.toml(生锈)package.json(Node.js)go.mod(去)pyproject.toml(Python,PEP 621)
遥测
可选的OpenTetry仪器,默认情况下禁用,并通过环境变量选择加入。
| 变量 | 目的 | 默认值 |
|---|---|---|
GIT_PRISM_OTLP_ENDPOINT | OTLP gRPC终结点URL。未设置时,遥测功能被禁用。 | 未设置(禁用) |
GIT_PRISM_OTLP_HEADERS | 计划中,尚未连接(#43).设置此变量今天无效;需要身份验证标头的托管OTLP后端需要一个本地收集器代理。 | 未设置 |
GIT_PRISM_SERVICE_NAME | 服务名称已报告给后端。 | git-prism |
GIT_PRISM_SERVICE_VERSION | 服务版本已报告给后端。 | 板条箱版本 |
快速开始使用Jaeger(任何兼容OTLP的后端都可以):
docker run -d --name jaeger -p 4317:4317 -p 16686:16686 jaegertracing/all-in-one:latest
GIT_PRISM_OTLP_ENDPOINT=http://localhost:4317 git-prism serve隐私: 不导出原始路径、文件内容、作者姓名或引用名称。路径是 SHA-256哈希;refs标准化为有界枚举。看 docs/telemetry.md.
贡献
看 贡献.md.
