pre-commit hook没生效因三点:未创建或赋权、路径错误、换行符/CRLF问题;eslint应只检查暂存JS文件并确认npx存在;flake8需过滤非源码路径且用python -m调用;commit-msg不能替代pre-commit做语法检查。

pre-commit hook 为什么没生效?检查这三点
Git 的 pre-commit hook 默认不自动启用,必须手动创建、赋予可执行权限,且不能放在远程仓库里——它只在本地工作目录的 .git/hooks/ 下起作用。常见错误是把脚本丢进项目根目录却忘了软链接或复制到正确路径,或者用 Windows 记事本保存导致换行符为 CRLF,Linux/macOS 下直接报 /bin/sh^M: bad interpreter。
实操建议:
- 在项目根目录运行
touch .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit - 用 VS Code、Vim 等编辑器打开该文件,确保文件编码为 UTF-8、换行符为
LF - 第一行必须是
#!/bin/sh(或#!/usr/bin/env bash),否则 shell 无法解析
用 eslint 检查 JavaScript 文件要绕过哪些坑?
直接在 pre-commit 里调 eslint 很容易只扫全部 .js 文件,但提交往往只改了几个文件——既慢又可能误报未改动的旧代码。更糟的是,如果项目没全局装 eslint,而用 npx eslint,又得确认 package.json 里有对应依赖,否则 hook 会静默失败(Git 默认忽略非 0 退出但不报错)。
实操建议:
- 只检查本次暂存区的 JS 文件:
git diff --cached --name-only --diff-filter=ACM | grep '\.js$' | xargs -r eslint - 用
npx eslint前加判断:command -v npx >/dev/null 2>&1 || { echo "npx not found"; exit 1; } - 加
--quiet避免 warning 干扰,只让 error 阻断提交:npx eslint --quiet --format=unix
Python 项目用 pre-commit 和 flake8 怎么避免误伤?
flake8 默认对所有 Python 文件严格检查,但有些自动生成的文件(如 __pycache__/、migrations/)不该参与校验;另外,如果开发者本地没装 flake8,hook 直接崩溃退出,Git 就卡住不提示原因。
实操建议:
- 过滤掉非源码路径:
git diff --cached --name-only --diff-filter=ACM | grep '\.py$' | grep -vE '(migrations|__pycache__|venv|\.venv)' - 用
python -m flake8替代裸命令,兼容 virtualenv 环境 - 加
|| true在调试阶段临时绕过阻断,方便观察输出;正式启用前务必删掉
commit-msg hook 能否替代 pre-commit 做语法检查?
不能。commit-msg hook 运行时机在 pre-commit 之后,此时代码已通过语法检查并暂存完毕,它只能检查提交信息格式(比如是否符合 Conventional Commits),对源码毫无约束力。有人误以为“只要不让 commit 成功就行”,但等走到这一步,问题代码已经进入暂存区,违背了“提交前拦截”的初衷。
关键区别:
-
pre-commit:修改暂存区文件后触发,返回非 0 则中止提交流程 -
commit-msg:仅读取.git/COMMIT_EDITMSG,无法访问或修改代码 - 真正需要多语言支持时,推荐用
pre-commit.com框架统一管理,而不是手写一堆 shell 脚本——后者容易在团队协作中因环境差异失效
Hook 是本地行为,不会自动同步给协作者;哪怕写得再完美,别人 clone 后照样不生效。真要落地,得配合文档说明、或用 husky(JS)/pre-commit(Python)这类工具自动生成和安装逻辑,否则就只是你电脑上一段漂亮的废代码。

















