Git

Pre Commit Hook

title: 预提交钩子(Pre-commit hooks) description: Git 的 pre-commit hook 用来在提交代码前执行一些检查或操作

title: 预提交钩子(Pre-commit hooks) description: Git 的 pre-commit hook 用来在提交代码前执行一些检查或操作

Brief

Git 钩子已经存在很久了,但我们认为它们依然没有被充分利用。随着 AI 辅助与智能体式编程(agentic coding)的兴起,意外提交密钥或有问题的代码的风险正在增加。虽然已有很多代码校验机制(比如持续集成 CI),但预提交钩子是一种简单而有效的安全防线,值得更多团队采用。

不过,如果在钩子中塞入大量运行缓慢的检查,会让开发者不愿意使用它们。因此,最好保持预提交钩子“精简”和“聚焦”,只做那些在工作流的这一阶段最适合发现的高价值风险,比如密钥扫描(secret scanning)。

来源:技术雷达

Guide

一、为什么预提交钩子在 AI 时代更重要?

  1. AI 生成代码的“过度自信”问题
    AI 工具(包括智能体型 Coding Agent)能快速生成大量代码、配置和脚本,其中可能包含:
    • 硬编码的访问密钥、Token、密码
    • 临时调试代码(如关闭鉴权、跳过校验)
    • 不符合团队规范的接口调用或依赖

    在高速度迭代下,开发者很容易“复制-粘贴-提交”,预提交钩子相当于最后一道“本地闸门”。
  2. 补充而不是替代 CI / 代码审查
    • CI 更适合:完整测试、构建、静态分析、复杂安全扫描。
    • Pre-commit 更适合:极快速、与“变更内容”强绑定的检查。

    换句话说,预提交钩子是“低成本、即时反馈”;CI 是“高覆盖、稍延时反馈”。
  3. 把错误截断在最便宜的阶段
    错误在不同阶段被发现的成本呈指数上升: $$本地开发 < pre-commit < PR 代码审查 < CI < 生产环境$$
    预提交钩子的目标就是:在提交之前阻止显而易见的错误泄漏到后续环节

二、预提交钩子适合放哪些检查?

原则:秒级完成、直接作用于当前变更、价值高于打扰成本

  1. 密钥 / 凭证扫描(强烈推荐)
    • 检查是否存在:
      • 类似 $$AWS_SECRET_ACCESS_KEY$$、$$GITHUB_TOKEN$$ 等特征字符串
      • 私钥文件:$$*.pem$$、$$*.key$$
      • 高熵字符串(疑似随机生成的密钥)
    • 可使用的工具:
      • git-secretsgitleakstrufflehog
    • 策略:
      • 提交前一旦发现疑似密钥,直接拒绝提交并给出清理建议
  2. 基础格式化与简单静态检查
    目的不是“找出一切问题”,而是:
    • 自动修正能自动修的(格式化、简单 lint)
    • 减少 PR 上来回评论“多了个空格”这类低价值沟通

    例如:
    • 自动格式化:prettierblackgofmt
    • 关键的快速 Lint:例如只对变更文件执行 eslint --max-warnings=0(简单规则集)
  3. 禁止明显危险的文件 / 内容进入仓库
    • 阻止:
      • 大体积二进制文件(超过某阈值)
      • 临时文件:*.log.DS_Store
      • 生成产物:dist/build/
    • 好处:控制仓库体积,避免把可再生成的内容纳入版本控制。
  4. 基础安全与合规性检查(轻量版)
    • 示例:
      • 在特定目录下禁止出现 evalexec(例如在用户输入可达路径)
      • 禁止导入不允许使用的库(比如内部安全策略禁止的 HTTP 客户端)
    • 要求:匹配规则简洁,运行极快(文本扫描级别,不要做复杂 AST 分析)。

三、预提交钩子不适合放什么?

  1. 运行时间超过 5–10 秒的大型检查
    • 例如:完整测试套件、全量 SAST、复杂依赖漏洞扫描等。
    • 放在 CI / CD 阶段更合理,否则开发者会想办法绕过 pre-commit(如 --no-verify)。
  2. 高误报、频繁中断开发流的规则
    • 若触发率过高、规则解释不清晰,会引发:
      • 团队抵触
      • 滥用跳过选项、局部关闭规则
    • 设计时要有“用户体验”意识:每次打断都要值得
  3. 与仓库无关或团队共识不足的强制规范
    • 例如在项目里强制执行某些高度个人化的风格(无共识),容易引起反感。
    • 建议:与团队讨论达成共识后再固化到 pre-commit。

四、如何设计一个“精简而高效”的 pre-commit 策略?

可以遵循一个三层分工模型:

  1. 本地 pre-commit:只做高速、高价值的检查
    • 密钥 / 凭证扫描
    • 格式化 + 基础 lint
    • 阻止大文件、临时文件
  2. CI 上的“变更集”检查
    • 对 PR 改动文件做更深入的:
      • 静态分析(更完整规则集)
      • 单元测试 / 快速集成测试
  3. Nightly / 定期全仓库扫描
    • 完整安全扫描、许可证合规、依赖漏洞、全量代码质量评估等。

这样一来:
$$开发体验良好 \ \cap \ 安全与质量门槛稳定提升$$

五、示例:使用 pre-commit 框架快速落地

对多语言项目,可以使用 pre-commit(Python 社区的那个工具),支持集中管理 Git 钩子。

示例配置: 在仓库根目录创建 .pre-commit-config.yaml

repos:
  # 1. 清理无用空白、修正行尾换行等
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-added-large-files   # 阈值可配置

  # 2. 密钥扫描(示例使用 gitleaks)
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

  # 3. 示例:对 JS/TS 使用 prettier 自动格式化
  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v4.0.0-alpha.8
    hooks:
      - id: prettier
        files: "\\.(js|jsx|ts|tsx|json|css|md)$"

安装并启用:

pip install pre-commit
pre-commit install   # 在 .git/hooks 配置 pre-commit

之后每次 git commit,这些检查都会在本地自动运行。

六、团队落地与推广建议

  1. 从最小可用集合开始
    • 第一步只上:密钥扫描 + 基础格式化 + 大文件检查
    • 观察一段时间后,根据反馈逐步添加其他规则。
  2. 给开发者提供“快速修复指引”
    • 不只是报错信息,更要告诉开发者:
      • 问题是什么?
      • 如何一条命令修复(例如:npm run lint-fixprettier --write ...
      • 若是疑似密钥,提示使用环境变量 / 密钥管理服务并从历史中清理。
  3. 建立“允许临时跳过,但要留痕”的机制
    • 比如约定:
      • 只有在特殊情况下允许 git commit --no-verify
      • 在 PR 描述中写明原因
    • 这样在保持灵活性的同时,降低滥用风险。
  4. 将 pre-commit 规则视为“团队契约”
    • 不要个人随意修改;
    • 通过 PR 调整,团队评审后合入,保证所有人理解这些检查的价值。

总结

  • 预提交钩子是 AI 时代防止意外提交密钥、危险代码的一道“本地防线”。
  • 关键在于:轻量、高频、高价值,而不是“把所有检查都塞进去”。
  • 推荐至少启用:
    1)密钥 / 凭证扫描
    2)基础格式化 & 简单 lint
    3)阻止大文件、临时文件、生成产物进入仓库

Copyright © 2024 Lionad - CC-BY-NC-CD-4.0