【python】【Git】我给 AI 编程助手加了一道 Git 提交门
我给 AI 编程助手加了一道 Git 提交门
📦 本文所有代码与配置均来自真实开源项目:
- GitHub:https://github.com/Fengj0n/-Bookkeeping
- Gitee:https://gitee.com/fengj0n/bookkeeping
引言
我用 Cursor 开发了一个本地记账应用,技术栈是 Electron、Vue 3 和 SQLite。项目进入持续修改阶段后,我遇到的主要问题不是代码生成,而是交付确认:测试是否真的执行过,质量检查是否有统一标准,提交的代码是否就是刚刚检查过的版本。
为了解决这几个问题,我在项目中加入了三层机制:用 Skill 固定检查规则,用 Subagent 执行测试和审计,用 Git Hook 拦截未经检查的提交。
本文记录这套方案的完整落地过程:规则如何设计、代理如何分工、Hook 如何拦截、验证结果如何,以及它适合什么场景。
目录
- 一、从聊天约定到项目规则
- 1.1 口头要求无法形成稳定流程
- 1.2 Skill 固定检查协议
- 1.3 规则需要区分阻断项和提醒项
- 二、让代理执行检查,让 Git 负责拦截
- 2.1 三个 Subagent 的职责
- 2.2 pre-commit 是最后一道门
- 2.3 为什么必须检查通行证是否过期
- 2.4 Windows 环境的 Hook 注意事项
- 三、验证结果与适用边界
- 3.1 三种提交场景
- 3.2 一次真实的安全修复
- 3.3 适用场景与局限
- 结语
一、从聊天约定到项目规则
1.1 口头要求无法形成稳定流程
最初我通过对话告诉 AI:“跑一下测试”“检查一下安全问题”。这种方式有两个缺点。
第一,要求不会自动继承。每次新开会话,都要重新说明测试文件、运行命令和报告格式。第二,结果难以核验。AI 说"已经检查完成",并不等于命令真的执行过,也不等于检查覆盖了预期范围。
因此,问题不在于提示词写得够不够长,而在于项目缺少固定的检查协议:检查什么、怎样算通过、失败后如何处理,都没有被保存为项目文件。
1.2 Skill 固定检查协议
我把协议写入 .cursor/skills/:
.cursor/skills/
├── unit-test/SKILL.md
├── comment-check/SKILL.md
└── security-audit/SKILL.md
unit-test 规定测试文件和运行方式:
| 测试对象 | 文件位置 | 运行命令 |
|---|---|---|
| JavaScript 工具函数 | tests/*.test.js |
node tests/xxx.test.js |
| Electron 模块 | tests/electron/*-test.js |
npx electron tests/xxx-test.js |
| Python 游戏 | games/test_*.py |
python games/test_xxx.py |
它还规定每条用例输出 PASS 或 FAIL!,全部通过时退出码必须为 0,并在项目根目录生成 test-report.md。
security-audit 的检查范围包括密码、Token、私钥、SQL 拼接、路径穿越、XSS、Electron 隔离配置和明文配置。comment-check 则检查函数注释、核心逻辑注释,以及注释是否与实际代码一致。
这些规则的作用是把"注意测试"和"检查安全"转换成可执行的检查项。检查结果有了固定格式,后续才能被代理和 Git Hook 使用。
1.3 规则需要区分阻断项和提醒项
如果所有问题都阻止提交,质量门禁会变得难以使用。因此我把检查结果分成两类。
阻断项包括:测试失败、严重或高危安全问题、注释与代码不一致。注释数量不足、表达不够通俗等问题仍然写入报告,但暂不阻止提交。
这是一个针对个人项目的取舍:先拦截会影响功能和安全的错误,再逐步改善代码可读性。团队项目可以根据风险等级调整这个标准。
二、让代理执行检查,让 Git 负责拦截
2.1 三个 Subagent 的职责
项目中配置了三个代理:
.cursor/agents/
├── tester.md
├── quality-engineer.md
└── gitcommit-agent.md
tester 只负责单元测试。它读取 unit-test 技能,执行现有测试,生成报告。只有所有测试退出码为 0 且没有 FAIL! 时,才生成:
.quality-gate/test-passed.flag
quality-engineer 负责安全审计和注释检查。达到项目规定的阻断标准后,生成:
.quality-gate/quality-passed.flag
gitcommit-agent 是流程编排者,不重新实现测试和审计逻辑。用户调用:
/gitcommit-agent
它按以下顺序工作:
删除旧通行证
↓
运行 tester
↓
运行 quality-engineer
↓
确认两张通行证有效
↓
git add + git commit
每轮检查开始前删除旧通行证,是为了避免上一轮的结果被误用于本轮代码。
2.2 pre-commit 是最后一道门
Subagent 解决了"如何完成检查",但不能阻止用户绕过代理直接提交:
git add .
git commit -m "保存修改"
所以我配置了 Git 的 pre-commit Hook:
hooks/pre-commit
scripts/check-quality-gate.js
Hook 文件只调用 Node 脚本:
#!/bin/sh
node scripts/check-quality-gate.js
通过下面的命令启用:
git config core.hooksPath hooks
脚本检查两张通行证是否存在,以及通行证是否对应当前暂存区的代码。
2.3 为什么必须检查通行证是否过期
只判断标记文件存在会产生错误放行:
周一:测试通过,生成通行证
周二:修改代码
周三:直接提交
周一的通行证不能证明周二的修改没有问题。因此脚本读取暂存区文件:
const staged = execSync(
'git diff --cached --name-only --diff-filter=ACMR',
{ encoding: 'utf8' }
).split('\n').filter(Boolean)
然后比较文件时间。如果任一暂存文件比通行证更新,提交就会被拒绝:
if (newestSourceMs > oldestMarkerMs + 2000) {
console.error('❌ 提交被拦截:通行证已过期')
process.exit(1)
}
2000 毫秒是 Windows 文件时间精度的容差。这个方案绑定的是文件修改时间,不是密码学签名,因此不能防止手工伪造通行证;它的目标是防止正常开发中的流程遗漏。如果需要更强的可信度,应在 CI 中重新执行测试和审计,而不是信任本地标记文件。
2.4 Windows 环境的 Hook 注意事项
Windows 编辑器可能把 Hook 保存为 CRLF,而 Hook 通常由 sh 执行,换行符错误会导致脚本运行失败。项目使用 .gitattributes 固定脚本使用 LF:
hooks/pre-commit text eol=lf
Hook 还需要保留可执行权限。换电脑或重新克隆项目后,需要再次执行:
git config core.hooksPath hooks
三、验证结果与适用边界
3.1 三种提交场景
我对门禁做了三次验证:
| 场景 | 结果 |
|---|---|
| 没有通行证直接提交 | 拒绝提交 |
| 使用早于代码修改时间的旧通行证 | 拒绝提交,并提示通行证过期 |
| 重新运行测试和质量检查后提交 | 允许提交 |
项目实际检查结果如下:
- JavaScript 测试:19/19 通过
- Python 测试:12/12 通过
- 严重安全问题:0
- 高危安全问题:0
- 注释与代码不一致:0
- 正式提交:
e31071a
提交时,Hook 输出了:
[质量门禁] ✅ 单元测试 + 质量检查两张通行证有效,放行
3.2 一次真实的安全修复
在质量检查过程中发现,项目原本试图通过 Electron 的 onHeadersReceived 为正式版页面注入 CSP。但正式版使用 loadFile() 加载 file:// 页面时,这种拦截方式不会生效。
后来改为在 index.html 中直接声明:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; style-src 'self' 'unsafe-inline'" />
这个问题说明,安全审计不能只搜索"有没有安全配置",还要确认配置是否适用于实际运行环境。
3.3 适用场景与局限
对个人项目或小型项目,这套方案的成本较低,适合解决以下问题:
- 测试经常被忘记执行
- 多个检查流程需要重复说明
- 提交结果依赖人工记忆
- 希望把项目规范随代码一起保存
它不适合被当作完整的安全系统。--no-verify 可以绕过本地 Hook,通行证也可以被手工伪造。因此团队项目仍应在 CI 中配置独立检查,把远程测试结果作为最终依据。
结语
这次实践的结果不是增加了几个 AI 配置文件,而是把一次提交拆成了几个可验证的步骤:Skill 保存标准,Subagent 执行标准,Git Hook 验证结果。
对我来说,最有用的变化是:提交代码前不再依赖"应该已经检查过了"这种判断,而是必须拿出测试结果和质量检查结果。
如果你也想在自己的项目中尝试类似的质量门禁,欢迎参考本文开头给出的开源仓库,.cursor/agents/ 和 .hooks/ 目录可以直接复用。
更多推荐




所有评论(0)