1
0
Files
nex/openspec/specs/git-hooks/spec.md
lanyuanxiaoyao c04a13bf8a refactor: 重写 Git hooks 体系,委托已有检查、新增模板与 LFS 校验
pre-commit 代码检查改为委托 _backend-lint / _versionctl-lint / _frontend-check,新增 LFS 指针校验;commit-msg 新增多行空行格式校验和模板注释忽略,移除 CJK/Python 字符集检测;新增 prepare-commit-msg 提交信息模板;hooks-install 增加 source 文件存在性校验;前端 check 补入 tsc -b 类型检查并修复暴露的类型错误
2026-05-06 13:44:28 +08:00

9.2 KiB
Raw Blame History

git-hooks

Purpose

定义仓库原生 Git hooks 的安装、校验、测试与跨平台执行规则,确保提交前快速检查和提交信息格式校验符合项目规范。

Requirements

Requirement: pre-commit hook 快速检查

pre-commit hook SHALL 在 git commit 执行前对 staged files 进行快速检查。非代码检查冲突标记、大文件告警、LFS 指针SHALL 在 _hooks-pre-commit 中直接实现代码检查Go 后端、Go versionctl、前端SHALL 根据 staged 文件类型有条件地委托给已有 Makefile target_backend-lint_versionctl-lint_frontend-check),不再内联独立的 lint 命令。

Scenario: 无 Go 和前端文件变更时跳过代码检查

  • WHEN staged files 中既无 .go 文件也无 .ts/.tsx/.scss 文件
  • THEN pre-commit hook SHALL 跳过代码检查委托,仅执行非代码检查

Scenario: Go 文件变更时委托后端 lint

  • WHEN staged files 中包含 backend/*.go 文件
  • THEN pre-commit hook SHALL 委托 _backend-lint target 进行 Go 代码检查
  • THEN _backend-lint SHALL 复用 backend/.golangci.yml 配置
  • THEN 若 lint 报告任何错误commit SHALL 被阻止

Scenario: versionctl Go 文件变更时委托 versionctl lint

  • WHEN staged files 中包含 versionctl/*.go 文件
  • THEN pre-commit hook SHALL 委托 _versionctl-lint target 进行 Go 代码检查
  • THEN _versionctl-lint SHALL 复用 versionctl/.golangci.yml 配置
  • THEN 若 lint 报告任何错误commit SHALL 被阻止

Scenario: 前端文件变更时委托前端检查

  • WHEN staged files 中包含 .ts.tsx.scss 文件
  • THEN pre-commit hook SHALL 委托 _frontend-check target 进行前端代码检查
  • THEN _frontend-check SHALL 运行 bun run check(包含 tsc -b TypeScript 类型检查、ESLint 和 Prettier 格式检查)
  • THEN 若检查报告任何错误commit SHALL 被阻止

Scenario: 冲突标记检测

  • WHEN staged files 中包含 <<<<<<<=======>>>>>>> 冲突标记
  • THEN pre-commit hook SHALL 报告错误并列出包含冲突的文件名
  • THEN commit SHALL 被阻止

Scenario: 大文件告警

  • WHEN staged files 中存在超过 500KB 的文本文件
  • THEN pre-commit hook SHALL 输出警告信息(不阻止提交),提示检查是否误提交

Scenario: LFS 指针校验

  • WHEN staged files 匹配 .gitattributesfilter=lfs 的路径模式
  • THEN pre-commit hook SHALL 检查 staged 内容是否为 LFS 指针格式(version https://git-lfs.github.com/spec/v1
  • THEN 若内容不是 LFS 指针格式commit SHALL 被阻止,并提示安装 git-lfs
  • THEN 若 staged files 不匹配任何 filter=lfs 路径模式SHALL 跳过此检查

Scenario: commit 被阻止时显示修复提示

  • WHEN pre-commit hook 检查失败
  • THEN hook SHALL 输出明确的修复提示(如 make lint 修复代码问题、手动解决冲突标记等)

Requirement: commit-msg hook 校验提交信息格式

commit-msg hook SHALL 在 git commit 输入提交信息后校验格式,确保首行符合项目规范。提交描述按项目规范应使用中文,但 hook SHALL NOT 通过 Python/CJK 字符集检测强制判断描述语言,以避免引入新的运行时依赖。

Scenario: 合法格式通过

  • WHEN 提交信息首行格式为 <类型>: <描述>,类型为 featfixrefactordocsstyletestchore 之一
  • THEN commit-msg hook SHALL 通过commit 正常执行

Scenario: 非法类型被拒绝

  • WHEN 提交信息首行使用的类型不在允许列表中(如 update: xxx
  • THEN commit-msg hook SHALL 报告错误显示允许的类型列表commit SHALL 被阻止

Scenario: 缺少冒号空格被拒绝

  • WHEN 提交信息首行为 feat:xxx(冒号后无空格)或 feat xxx
  • THEN commit-msg hook SHALL 报告格式错误commit SHALL 被阻止

Scenario: 首行过长告警

  • WHEN 提交信息首行超过 72 个字符
  • THEN commit-msg hook SHALL 输出警告(不阻止提交),提示首行应简短

Scenario: Merge commit 自动放行

  • WHEN 提交信息首行以 Merge 开头
  • THEN commit-msg hook SHALL 直接通过,不进行格式校验

Scenario: 格式错误时显示示例

  • WHEN commit-msg hook 检查失败
  • THEN hook SHALL 输出包含正确格式示例的错误信息(如 feat: 添加供应商批量管理功能

Scenario: 不执行字符集检测

  • WHEN 提交信息首行格式合法且类型合法,但描述部分不包含 CJK 字符(如 feat: add hook tests
  • THEN commit-msg hook SHALL 通过
  • THEN hook SHALL NOT 调用 python3 或其他额外运行时做 Unicode/CJK 检测

Scenario: 多行格式校验

  • WHEN 提交信息忽略 # 注释行后,第三行及之后存在任一非空详细说明行
  • THEN commit-msg hook SHALL 检查第二行是否为空行
  • THEN 若第二行非空行commit SHALL 被阻止,提示首行后应空行再写详细描述

Scenario: 模板注释不参与校验

  • WHEN 提交信息文件中包含 prepare-commit-msg 写入的 # 注释模板
  • THEN commit-msg hook SHALL 忽略这些注释行
  • THEN 注释行 SHALL NOT 导致首行格式、多行空行分隔校验失败

Requirement: hooks-install 安装命令

make hooks-install SHALL 将 scripts/git-hooks/ 下的 hook 脚本安装到 .git/hooks/,不覆盖 Git LFS 管理的 hook。

Scenario: 安装所有 hook 脚本

  • WHEN 执行 make hooks-install
  • THEN scripts/git-hooks/pre-commit SHALL 被复制到 .git/hooks/pre-commit
  • THEN scripts/git-hooks/commit-msg SHALL 被复制到 .git/hooks/commit-msg
  • THEN scripts/git-hooks/prepare-commit-msg SHALL 被复制到 .git/hooks/prepare-commit-msg
  • THEN 所有复制文件 SHALL 被设置为可执行(chmod +x

Scenario: 不覆盖 LFS 管理的 hook

  • WHEN .git/hooks/post-checkout.git/hooks/post-commit.git/hooks/post-merge.git/hooks/pre-push 已由 Git LFS 管理
  • THEN make hooks-install SHALL NOT 覆盖或修改这些文件

Scenario: 重复安装幂等

  • WHEN make hooks-install 被执行多次
  • THEN hook 文件 SHALL 被正确覆盖更新,不会产生重复或损坏

Scenario: hooks-check 验证安装状态

  • WHEN 执行 make hooks-check
  • THEN 命令 SHALL 检查 .git/hooks/pre-commit.git/hooks/commit-msg.git/hooks/prepare-commit-msg 是否存在且可执行
  • THEN SHALL 输出每个 hook 的安装状态

Scenario: 安装前验证 source 文件存在

  • WHEN 执行 make hooks-install
  • THEN 命令 SHALL 在复制前验证每个 source 文件(scripts/git-hooks/<hook-name>)是否存在
  • THEN 若 source 文件不存在,命令 SHALL 报告错误并返回非零退出码

Requirement: hooks-test 回归测试命令

make hooks-test SHALL 运行仓库内 hook 回归测试,覆盖 commit-msg 格式校验和 pre-commit staged-file 检查,不污染真实 git index。

Scenario: 运行 hook 回归测试

  • WHEN 执行 make hooks-test
  • THEN SHALL 运行 scripts/git-hooks/test-hooks.sh
  • THEN 测试 SHALL 使用临时 GIT_INDEX_FILE 构造 staged fixture
  • THEN 若任一 hook 行为不符合预期,命令 SHALL 返回非零退出码

Requirement: 跨平台可用

pre-commit 和 commit-msg hook 脚本 SHALL 可在 macOS 和 WindowsGit Bash上正常执行。

Scenario: macOS 上正常执行

  • WHEN hook 脚本在 macOS 上被 git 调用
  • THEN #!/bin/sh shebang SHALL 被系统正确解析
  • THEN exec make SHALL 正确调用 Makefile target

Scenario: Windows Git Bash 上正常执行

  • WHEN hook 脚本在 Windows 的 Git Bash 环境中被 git 调用
  • THEN Git for Windows 自带的 sh.exe SHALL 正确解析 #!/bin/sh
  • THEN exec make SHALL 正确调用 Makefile target依赖 Git Bash/MINGW64 环境中 make 可用)
  • THEN Go 和 Bun 工具链 SHALL 通过 PATH 可被 Makefile 调用

Requirement: pre-commit 核心逻辑在 Makefile 中复用

pre-commit hook 的检查逻辑 SHALL 通过 Makefile target 调用项目已有工具链不重复实现。非代码检查冲突标记、大文件、LFS 指针SHALL 在 _hooks-pre-commit 中直接实现;代码检查 SHALL 委托 _backend-lint_versionctl-lint_frontend-check target。

Scenario: Go lint 委托后端 lint target

  • WHEN pre-commit 需要检查 Go 文件
  • THEN SHALL 委托 _backend-lint_versionctl-lint target根据文件路径 backend/ vs versionctl/
  • THEN SHALL NOT 在 _hooks-pre-commit 中内联 golangci-lint 命令

Scenario: 前端检查委托前端 check target

  • WHEN pre-commit 需要检查前端文件
  • THEN SHALL 委托 _frontend-check target
  • THEN SHALL NOT 在 _hooks-pre-commit 中内联 eslintprettier 命令

Scenario: 终端直接调试

  • WHEN 开发者执行 make _hooks-pre-commit
  • THEN SHALL 执行与 pre-commit hook 完全相同的检查逻辑
  • THEN 输出 SHALL 与 hook 触发时一致