
概述传统Git只记录提交者却无法区分代码的「真实作者」是人还是AI生成。而各家AI工具都有自己的会话管理方式无法跨工具追踪。官网使用Rust实现、开源GitHub2.5K Star279 Fork追踪AI生成代码的Git插件用于追踪代码仓库中AI生成的代码将每行代码与其对应的AI Agent、模型和会话记录关联起来。官方文档。价值自动将每行AI生成的代码链接到生成它的Agent、模型和会话记录让你永远不会丢失代码背后的意图、需求和架构决策。功能特性git-ai blame是git blame的替代品显示每行代码的AI生成者Agent、模型、Session在git commit输出中显示人类/AI代码比例使用Git Notesrefs/notes/ai命名空间存储AI作者信息不修改提交历史通过git-ai stats统计不同Agent的代码贡献量/ask命令可直接向生成该代码的Agent提问理解代码背后的意图支持AgentClaude Code、Codex、Cursor、Windsurf、Copilot、Continue、Gemini、Junie、Rovo Dev、Amp等主流AI编程工具git-ai stats --json输出示例{human_additions:28,mixed_additions:5,ai_additions:76,ai_accepted:47,total_ai_additions:120,total_ai_deletions:34,time_waiting_for_ai:240,tool_model_breakdown:{claude_code/claude-sonnet-4-5-20250929:{ai_additions:76,ai_accepted:47,total_ai_additions:120,total_ai_deletions:34}}}统计字段详解字段含义示例human_additions纯人类贡献的代码行数28mixed_additionsAI生成但被人修改过的行数5ai_additionsAI贡献的总行数 (mixedaccepted)76ai_acceptedAI生成且未被修改的接受行数47total_ai_additionsAI生成的总行数120total_ai_deletionsAI删除的总行数34time_waiting_for_ai等待AI响应的累计时间秒240原理技术栈模块技术栈作用核心CLIRustclapsmolGit代理层Hook执行高性能计算差分算法imara-diff实现Git的Myers diff算法Git操作gix-configGit Plumbing读写Git Notes、blame、tree操作VSCode插件TypeScriptVSCode API监听编辑事件调用checkpointJetBrains插件KotlinIntelliJ Platform同上适配IntelliJ系列IDE存储格式JSON(Git Notes)SQLite(Prompt DB)AI归属日志Prompt历史三个核心设计Git Wrapper模式将git-ai安装为Git的代理拦截所有Git命令在commit、rebase、merge等关键节点插入HookGit Notes存储利用Git原生的Notes机制(refs/notes/ai)存储AI归属信息不污染commit历史Checkpoint机制引入检查点概念在AI或人类每次编辑后创建快照最终在commit时合并为完整的归属日志核心流程图Git Notes(refs/notes/ai)Git命令git-ai CLI(Git Wrapper)VSCode插件(agent-support)AI编程工具(Cursor)Git Notes(refs/notes/ai)Git命令git-ai CLI(Git Wrapper)VSCode插件(agent-support)AI编程工具(Cursor) 阶段 1: AI 生成代码 阶段 2: 用户 Commit 阶段 3: 查询归属 AI 生成代码片段通知编辑事件 (文件路径、会话ID)调用 checkpoint (kindAIagent)创建 Working Log (记录行级归属)git commitpre-commit hook 触发最终 checkpoint真正执行commit返回新commit SHApost-commit hook 生成 Authorship Log写入 Git Note (commit SHA - AI 归属)git-ai blame 文件读取 AI 归属数据返回数据展示每行代码的作者(AI模型/人类)实战基于命令行安装curl-sSLhttps://usegitai.com/install.sh|bash# Windowspowershell-NoProfile-ExecutionPolicyBypass-Commandirm https://usegitai.com/install.ps1 | iex# 2. 安装IDE钩子(自动检测并配置Cursor、VSCode等)git-ai install-hooks# 3. 使用AI工具编写代码然后commitgitcommit-mAdd feature with AI assistance# 4. 查看AI代码归属(类似git blame但显示AI信息)git-ai blame文件路径# 5. 查看统计信息git-ai status装好成功后git-ai在后台默默记录。可继续用git commit、git rebase、git merge等命令git-ai会自动处理AI归属信息的传播。源码源码结构.cargo .github .vscode agent-support asserts benches docs ←文档 packaging ←打包 scripts ←脚本 skills ←技能 specs/ ←契约驱动开发 src/ ├── mdm/ │ ├── agents/ │ │ ├── claude_code.rs ←CC hook安装器 │ │ ├── cursor.rs ←Cursor │ │ ├── windsurf.rs ←Windsurf │ │ └── ... ←其他Agent支持 │ └── hook_installer.rs ←Hook安装抽象接口(HookInstaller trait) ├── commands/ │ ├── checkpoint.rs ← Checkpoint 核心逻辑 (2000 行) │ ├── git_ai_handlers.rs ← CLI 命令分发 │ └── checkpoint_agent/ │ ├── agent_v1_preset.rs ← Hook input JSON 解析 │ └── agent_presets.rs ← AgentRunResult 定义 └── authorship/ ├── attribution_tracker.rs ← 行级别归属追踪 ├── working_log.rs ← Checkpoint 持久化 └── authorship_log.rs ← Authorship Log 格式 tests/值得学习架构精妙用Git Plumbing命令Git Notes实现一个完全Git-native的AI代码追踪系统性能开销100ms多平台适配统一接入支持Cursor、Claude Code、GitHub Copilot等10种AI工具Rust工程化利用 Rust 的 async、零成本抽象、类型系统实现了高性能的 Git 代理层Git Proxy无缝拦截Git命令参考src/commands/git_handlers.rs解读「Wrapper 而非 Fork」: git-ai 没有重新实现 Git 逻辑而是作为一个透明的中间人。用户执行git commit实际调用的是git-ai commit后者再调用真正的git。这保证了:「高兼容性」: 所有 Git 功能都能正常使用「零侵入性」: 不需要修改 Git 本身「信号转发的魔法」:在 Unix 系统上如果用户按CtrlC中断 Git 命令git-ai需要把信号正确转发给子进程但有一个例外: 「交互式终端」TTY 模式不能创建新进程组否则会收到SIGTTIN/SIGTTOU导致挂起代码通过libc::isatty()检测是否为交互式终端只在非交互模式创建新进程组如果创建了新进程组会安装全局信号处理器转发SIGTERM/SIGINT/SIGHUP/SIGQUIT到子进程「跨平台处理」:Unix: 使用pre_exec钩子设置进程组安装信号处理器Windows: 使用CREATE_NO_WINDOWflag 隐藏窗口(非交互模式)Git 命令路径通过config::Config::get().git_cmd()获取支持用户自定义「性能监控」:每个 Git 命令都会记录 pre-hook、git 执行、post-hook 的耗时如果总耗时超过目标值(100ms)会记录性能日志用于优化异步 I/O 的使用在 checkpoint 模块中(稍后展示)启示「Wrapper 模式的威力」: 不需要重写整个系统在外面包一层代理就能扩展功能同时保障兼容性「交互式 vs 非交互式」: 进程管理要区分场景TTY 模式和后台运行的信号处理逻辑完全不同「性能监控的重要性」: 每个 Hook 都记录耗时发现性能瓶颈后才能优化Checkpoint精准追踪这行代码是谁改的参考src/commands/checkpoint.rs解读增量计算的智慧第一次遇到文件时用git blame反推历史归属(谁在之前的 commit 改过这行)后续编辑时只需要基于上一个 checkpoint 的状态做 diff避免重复计算这就像 Git 本身的快照 增量设计性能极高Feature Flag控制Blame行为letai_blameifConfig::get().get_feature_flags().inter_commit_move{repo.blame(file_path,ai_blame_opts).ok()}else{None// 跳过 blame,所有行默认为 human};inter_commit_moveflag 控制是否使用git blame反推历史归属关闭时所有历史行都标记为human性能更好但会丢失跨 commit 的 AI 归属追踪开启时可以检测到用户复制粘贴 AI 代码的情况「行级归属 vs 字符级归属」: 代码中有LineAttribution和Attribution两种数据结构:为什么需要两种?因为当文件内容变化时「行号会变但字符偏移更稳定」(配合 diff 算法)。最终输出时再转回行号给用户看。LineAttribution: 给人看的(第 10-15 行是 AI-xxx 写的)Attribution: 内部使用的字符范围(第 120-450 个字符是 AI-xxx 写的)「AttributionTracker 的核心算法」: 这是整个系统最复杂的部分,它要解决一个难题——「当文件被编辑后,如何更新每个字符的归属?」保留所有历史作者信息用于后续的git-ai blame查询启示「增量计算是性能的关键」: 基于上一个 checkpoint 做 diff避免重复计算提升性能「数据结构要为业务服务」: 行号给人看(LineAttribution)字符偏移给算法用(Attribution)各司其职「Feature Flag 控制复杂度」:inter_commit_moveflag 让用户在性能和准确性之间权衡「异步并发的威力」: 使用smolSemaphore8 个并发任务处理 100 文件性能提升 3-5 倍「善用成熟算法」:imara-diff实现了 Git 的 Myers diff 算法不要重复造轮子多工具适配统一支持10种AI工具参考src/commands/install_hooks.rs、agent-support/vscode/src/extension.ts、agent-support/vscode/src/ai-edit-manager.ts//exportclass AIEditManager{privatesnapshotOpenEventsnewMapstring,{timestamp:number;count:number;uri:vscode.Uri;}();// 关键设计 3: 捕获 Snapshot 打开事件 publichandleOpenEvent(doc:vscode.TextDocument):void{// VSCode Copilot/Claude 在生成代码时会先打开一个特殊的 snapshot 文档if(doc.uri.schemechat-editing-snapshot-text-model||doc.uri.schemechat-editing-text-model){constfilePathdoc.uri.fsPath;constnowDate.now();this.snapshotOpenEvents.set(filePath,{timestamp:now,count:(this.snapshotOpenEvents.get(filePath)?.count||0)1,uri:doc.uri// 保存 URI,稍后解析 sessionId});// 在 AI 编辑前触发 human checkpoint (记录基准状态)console.log([git-ai] Snapshot open event detected, triggering human checkpoint);this.triggerHumanCheckpoint([filePath]);}}// 关键设计 4: 文件保存时检查是否为 AI 编辑publichandleSaveEvent(doc:vscode.TextDocument):void{constfilePathdoc.uri.fsPath;// Debounce: 300ms 后评估setTimeout((){this.evaluateSaveForCheckpoint(filePath);},300);}privateevaluateSaveForCheckpoint(filePath:string):void{constsnapshotInfothis.snapshotOpenEvents.get(filePath);// 如果有对应的 snapshot 打开事件则是 AI 生成的if(snapshotInfosnapshotInfo.count1snapshotInfo.uri?.query){constsnapshotAgeDate.now()-snapshotInfo.timestamp;// 检查 snapshot 是否太旧( 10 秒则忽略)if(snapshotAge10000){console.log([git-ai] Snapshot too old, skipping AI checkpoint);return;}// 关键设计 5: 从 URI Query 解析 Session IDtry{constparamsJSON.parse(snapshotInfo.uri.query);letsessionIdparams.chatSessionId||params.sessionId;// VSCode 可能把 sessionId 编码在 chatSessionResource.path 中if(!sessionIdparams.chatSessionResource?.path){sessionIdBuffer.from(params.chatSessionResource.path.slice(1),base64).toString(utf-8);}if(sessionId){// 读取会话历史文件 (VSCode 自动保存的 .jsonl)constchatSessionPathpath.join(storagePath,chatSessions,${sessionId}.jsonl);// 调用 git-ai checkpointthis.checkpoint(ai,JSON.stringify({hook_event_name:after_edit,chat_session_path:chatSessionPath,// 包含完整 prompt 历史session_id:sessionId,edited_filepaths:[filePath],workspace_folder:workspaceFolder.uri.fsPath,dirty_files:this.getDirtyFiles(),// 所有未保存的文件内容}));}}catch(e){console.error([git-ai] Failed to parse snapshot URI,e);}}// 清理this.snapshotOpenEvents.delete(filePath);}}解读「插件式架构的可扩展性」:每个 AI 工具对应一个AgentInstallertrait 实现新增工具支持只需实现check_hooks()和install_hooks()两个方法主流程完全不用改完美体现了开闭原则「配置文件注入的巧妙手法」:对于 VSCode/Cursor: 修改settings.json添加git.path: /path/to/git-ai对于 JetBrains: 修改~/.config/JetBrains/xxx/options/git.xml关键点: 「让 IDE 以为在调用git实际调用的是git-ai」「VSCode 插件的巧妙检测机制」「不是用启发式规则判断」而是利用 VSCode 内部机制当 Copilot/Claude 生成代码时VSCode 会先创建一个临时的 「snapshot 文档」URI scheme 是chat-editing-snapshot-text-modelgit-ai 插件监听onDidOpenTextDocument事件捕获这些特殊snapshot打开当文件保存时检查是否有对应snapshot记录如果有说明是AI编辑零误判这不是启发式规则而是利用IDE的内部信号准确率100%Session ID的获取方式// 从 snapshot URI 的 query 参数解析constparamsJSON.parse(snapshotInfo.uri.query);letsessionIdparams.chatSessionId||params.sessionId;// VSCode 把 sessionId Base64 编码在 chatSessionResource.path 中if(!sessionIdparams.chatSessionResource?.path){sessionIdBuffer.from(params.chatSessionResource.path.slice(1),base64).toString(utf-8);}为什么这么做?「利用 VSCode 的内部数据」: snapshot URI 的 query 包含了会话信息「获取完整 Prompt 历史」:chatSessions/${sessionId}.jsonl是 VSCode 自动保存的会话记录包含所有对话内容「零配置」: 不需要 AI 工具主动上报直接从 IDE 的内部数据中拿出来启示「面向扩展的设计」: 插件式架构让系统具备无限扩展能力「配置文件注入」: 很多时候不需要修改应用本身改配置文件就能实现 Hook「利用平台内部机制」: 与其猜测用户行为(启发式)不如深挖平台的内部信号(snapshot URI)「数据寄生策略」: VSCode 已经保存了会话历史(.jsonl)git-ai 直接读取不需要重复收集git-ai目前只能记录每一行代码的来源但是没有统计的功能。为了方便管理支持看团队多个仓库的AI生成代码行数占比或采纳率占比开源了一个分析和查询工具。https://github.com/ForeverPx/ai-code-metrics