Git Hooks的pre-commit脚本可实现本地代码语法校验与自动格式化:一、启用并编写含set -e/-u的Shell脚本;二、用git diff --cached筛选待提交文件,调用flake8/eslint等检查;三、用prettier/black修复后git add回暂存区;四、支持跳过校验、清晰报错及多语言分发处理,并建议符号链接共享脚本。

在代码提交前自动进行语法校验与格式化,能显著提升团队代码质量并减少人工干预。Git Hooks(特别是 pre-commit)配合 Shell 脚本是最轻量、最可控的实现方式,无需引入复杂 CI 工具即可在本地拦截问题。
一、启用 pre-commit Hook 并编写基础 Shell 脚本
Git 的 .git/hooks/pre-commit 是一个可执行脚本,在每次 git commit 前自动运行。它默认是 shell 脚本,只需确保有执行权限:
- 进入项目根目录,执行:
chmod +x .git/hooks/pre-commit - 若无该文件,新建并编辑:
touch .git/hooks/pre-commit && vim .git/hooks/pre-commit - 脚本开头必须包含
#!/bin/bash,并建议添加set -e(出错即退出)和set -u(未定义变量报错)增强健壮性
二、校验:用 linters 检查暂存区中待提交的代码
只检查将要提交的文件(即 git diff --cached --name-only 输出),避免全量扫描拖慢提交流程。以 Python 和 JavaScript 为例:
抓取指定 GitHub用户的 Stars 项目,生成标准化中文 Markdown 报告。用户提及「分析 GitHub stars」「导出收藏项目」「汇总 GitHub 星标」「生成 stars 报告」或粘贴含 ?tab=stars 的链接时触发。执行通过 bash...
- Python:用
pylint或flake8,例如:git diff --cached --name-only --diff-filter=ACM | grep '\.py$' | xargs -r flake8 --max-line-length=88 - JavaScript:用
eslint,例如:git diff --cached --name-only --diff-filter=ACM | grep '\.js$' | xargs -r eslint --quiet --fix-dry-run(--fix-dry-run仅报告可修复项,不实际修改) - 关键点:用
--diff-filter=ACM只捕获新增(A)、已修改(M)、重命名后内容变更(C)的文件,跳过删除或未变更文件
三、格式化:自动修复并重新暂存,保持提交原子性
若检测到可自动修复的问题(如 Prettier、Black),应在 hook 中完成格式化并 git add 回暂存区,否则 commit 会因未暂存修改而失败:
- 示例(JS):
git diff --cached --name-only --diff-filter=ACM | grep '\.js$' | xargs -r prettier --write && git add $(git diff --cached --name-only --diff-filter=ACM | grep '\.js$') - 示例(Python):
git diff --cached --name-only --diff-filter=ACM | grep '\.py$' | xargs -r black --quiet && git add $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$') - 注意:格式化命令需支持静默模式(如
--quiet)避免干扰输出;git add必须显式指定文件,不能用git add .,防止误提交未暂存的其他改动
四、增强体验:跳过校验、提示友好错误、支持多语言混合项目
生产级 hook 需兼顾开发效率与约束力:
- 支持临时跳过:
git commit --no-verify或在脚本开头判断if [[ "$1" == "--no-verify" ]]; then exit 0; fi(但更推荐用环境变量如SKIP_LINT=1 git commit) - 错误提示清晰:对每类文件分别运行检查,失败时打印具体文件名和错误摘要,避免“脚本退出码 1”这类模糊信息
- 按后缀分发处理逻辑:用
case语句匹配.py、.js、.ts、.md等,调用对应工具,避免单个工具缺失导致整个 hook 失败(可用command -v xxx && xxx ... || echo "xxx not found, skip")
不复杂但容易忽略:hook 是本地行为,无法强制他人使用;建议将脚本纳入项目仓库(如 scripts/pre-commit),再通过 ln -sf ../scripts/pre-commit .git/hooks/pre-commit 符号链接,并在 README 中说明初始化方式,让新成员一键启用。

















