pre-commit钩子失败主因是下游命令报错,非husky自身问题;需检查lint-staged等实际执行命令、path环境、node版本,并确保格式化后执行git add回填暂存区。

pre-commit 钩子执行失败:常见报错和定位方法
当你在 VSCode 中点击「提交」后弹出 husky > pre-commit hook failed,说明钩子脚本中途退出(非 0 状态)。这不是 Husky 本身的问题,而是它忠实转发了下游命令的错误。
关键排查点:
-
pre-commit脚本里实际执行的命令(比如npx lint-staged或npm run lint)是否报错?打开 VSCode 底部状态栏的「输出」面板,切换到「Git」或「Tasks」标签页,看完整错误栈 - 脚本中用了
set -e(Husky v8+ 默认启用),任何一行失败都会中断——这意味着git add失败、Prettier 写入权限不足、甚至 Node.js 版本不兼容都可能触发 - VSCode 内置终端和系统终端的 PATH 可能不同,导致
npx找不到本地安装的工具;建议在.husky/pre-commit开头加echo $PATH对比验证
如何让 pre-commit 只处理暂存区文件,而不是整个项目
直接写 npx prettier --write . 会扫全量文件,慢且危险(比如误格式化 node_modules 或生成代码)。正确做法是只操作 git add 过的文件。
推荐两种稳定写法:
- 用
lint-staged(最常用):在package.json中配置"lint-staged"字段,然后pre-commit脚本只写npx lint-staged。它会自动调用git diff --cached提取暂存文件 - 手动过滤(适合轻量项目):在
.husky/pre-commit里写npx prettier --write $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|json)$')。注意--diff-filter=ACM只选新增/修改/重命名的文件,避免对已删除文件操作报错
VSCode 提交面板不显示模板,但 husky commit-msg 钩子却生效
这是典型配置错位:提交消息模板由 Git 本身控制,和 Husky 的 commit-msg 钩子无关。VSCode 源代码管理面板是否加载模板,只取决于 git config commit.template 是否指向有效路径。
检查与修复步骤:
- 运行
git config --get commit.template,确认返回的是项目内存在的文件路径(如.gitmessage.txt) - 如果路径正确但 VSCode 不显示,可能是文件编码问题——确保
.gitmessage.txt是 UTF-8 无 BOM 格式,且末尾有空行(Git 要求) -
commit-msg钩子校验失败时,VSCode 会弹出错误提示,但它不负责渲染模板;模板渲染完全由 Git + VSCode 的集成逻辑完成,和 Husky 无依赖关系
为什么 pre-commit 后代码没自动 git add?
因为 Husky 默认不帮你回填暂存区。比如 prettier --write 修改了文件,但 Git 仍认为它是「已修改未暂存」,提交会跳过这些变更——结果就是「格式化了却没提交进去」。
解决方案分两层:
- 若用
lint-staged:在它的配置里显式加上"git add",例如:"*.{js,ts}": ["eslint --fix", "prettier --write", "git add"] - 若手写脚本:在
prettier命令后追加&& git add .,但注意这会把所有修改都暂存,不够精准;更稳妥的是&& git add $(git diff --name-only --cached),只重新添加刚才被格式化的那些暂存文件
这个细节极易被忽略:VSCode 提交界面只提交「当前暂存区」,不会自动包含你刚格式化但没 git add 的文件。











