Tips & Tricks (更新: 2026/6/2)

用 Claude Code 配置 Husky + lint-staged:提交前质量检查实战

用 Claude Code、Husky 和 lint-staged 在提交前自动运行 ESLint 与 Prettier,兼顾质量和速度。

用 Claude Code 配置 Husky + lint-staged:提交前质量检查实战

Claude Code 很适合一次性修改多个文件:组件、测试、配置、文档可能在同一次会话里一起变化。问题是,变化越多,人工评审越容易被格式差异、未使用的 import、Markdown 空格这类细节分散注意力。真正需要人判断的是行为是否正确、接口是否清晰、产品意图是否被满足。

Husky + lint-staged 的价值就在这里。Git hook 是 Git 在提交、推送等动作前后执行的小脚本;Husky 负责把这些 hook 放进仓库,方便团队共享;lint-staged 只对已经 git add 的文件运行命令,避免每次提交都扫描整个项目。Claude Code hooks 是 Claude Code 生命周期里的自动化能力,和 Git hook 不是同一件事。它能提醒或限制 Claude Code 的行为,但不能保护普通终端、编辑器或其他工具产生的提交。

本文的目标不是把本地 pre-commit 变成完整 CI,而是把便宜、快速、确定的检查自动化,把昂贵的类型检查、测试和构建放到 pre-push 或 CI。

工作流全貌

我在实际项目里更推荐这种分层:pre-commit 做文件级检查,pre-push 做项目级检查,CI 做最终裁决。这样既能减少低级问题,又不会让开发者因为等待太久而习惯性使用 --no-verify

flowchart LR
  A["Claude Code 修改文件"] --> B["开发者选择并 git add"]
  B --> C["Husky pre-commit"]
  C --> D["lint-staged"]
  D --> E["ESLint / Prettier"]
  E --> F["commit"]
  C --> G["类型检查、测试、构建放到 pre-push 或 CI"]

本文参考的官方资料包括 Husky Get startedlint-staged READMEGit hooks 文档Claude Code hooks reference。当前 Husky 推荐使用 npx husky init 初始化,lint-staged 则需要一个 pre-commit hook 和一份按文件 glob 映射命令的配置。

最小可运行配置

如果项目里的 ESLint 或 Prettier 还不稳定,先看 Claude Code ESLint 配置指南Prettier 配置指南。Husky 只是入口,真正执行的是这些底层命令。

让 Claude Code 帮你改时,不要只说“加一个 pre-commit”。更好的提示是明确范围、速度和边界:

请给这个 Node.js/TypeScript 仓库加入 Husky 和 lint-staged。
pre-commit 只处理已暂存的 JS、TS、JSON、Markdown、CSS 文件。
在 pre-commit 里运行 ESLint 自动修复和 Prettier。
类型检查、测试、构建不要放进 pre-commit,请放到 pre-push 或 CI。
完成后列出我应该手动验证的命令。

手动安装也很直接:

npm install --save-dev husky lint-staged eslint prettier
npx husky init

npx husky init 会创建 .husky/pre-commit,并在 package.json 中加入或更新 prepare 脚本。把生成的 hook 内容改成下面这样:

#!/usr/bin/env sh
npx lint-staged

然后在 package.json 中加入 lint-staged 配置。如果已有 scripts,请合并键值,不要整段覆盖。

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint --fix .",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "prepare": "husky"
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix --max-warnings=0",
      "prettier --write"
    ],
    "*.{json,md,mdx,yml,yaml,css,scss}": [
      "prettier --write"
    ]
  }
}

验证时,故意制造一个格式不整齐的文件并暂存它:

git add src/example.ts
npx lint-staged --debug
git commit -m "chore: verify pre-commit checks"

--debug 会显示读取了哪份配置、哪些文件命中了 glob、实际执行了什么命令。排查失败时,把这段输出交给 Claude Code,比让它凭空猜测可靠得多。

更适合长期维护的配置

仓库变大后,我更倾向把配置移动到 lint-staged.config.mjs。这样 package.json 更干净,也可以写辅助函数。下面的例子会给文件名加引号,避免路径中有空格时命令失败。

// lint-staged.config.mjs
const shellQuote = (file) => `"${file.replaceAll('"', '\\"')}"`;
const joinFiles = (files) => files.map(shellQuote).join(" ");

export default {
  "*.{js,jsx,ts,tsx}": (files) => [
    `eslint --fix --max-warnings=0 ${joinFiles(files)}`,
    `prettier --write ${joinFiles(files)}`,
  ],
  "*.{json,md,mdx,yml,yaml,css,scss}": (files) =>
    `prettier --write ${joinFiles(files)}`,
};

使用这个文件后,请删除 package.json 里的 lint-staged 字段。两份配置会制造维护成本,也会让 Claude Code 不确定应该更新哪一份。

三个真实使用场景

第一个场景是 TypeScript 产品应用。Claude Code 经常同时修改组件、测试和工具函数。pre-commit 只运行 ESLint 自动修复和 Prettier,就能去掉大量低价值 review 噪音。完整类型检查需要项目上下文,放到 pre-push 或 CI 更合适。

第二个场景是 Astro 或 Next.js 内容站。文章、MDX、JSON 元数据和 CSS 经常一起变。lint-staged 能让即将提交的文件保持统一格式,评审者可以专注看文章质量,而不是被空格和换行干扰。

第三个场景是 monorepo。不要在 pre-commit 里跑所有包的测试。更稳的做法是先对暂存文件做格式化和 lint,再让任务运行器或 CI 根据路径决定要跑哪些包的测试。给 Claude Code 的规则可以写成:pre-commit 要快,pre-push 做中等检查,CI 做完整检查。

commit-msg 与 pre-push 的分工

提交信息校验应该放在独立的 commit-msg hook。如果团队使用 Conventional Commits,可以用 commitlint。

npm install --save-dev @commitlint/cli @commitlint/config-conventional
// commitlint.config.mjs
export default {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "subject-max-length": [2, "always", 72],
  },
};
#!/usr/bin/env sh
npx --no -- commitlint --edit "$1"

把最后一段放进 .husky/commit-msg。构建、测试和类型检查则放到 .husky/pre-push

#!/usr/bin/env sh
npm run validate

对应的 package.json 可以这样组织:

{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "test:ci": "vitest run --coverage",
    "build": "vite build",
    "validate": "npm run typecheck && npm run lint && npm run format:check && npm run test:ci && npm run build"
  }
}

这样 Claude Code 看到 pre-commit 失败时,会优先检查暂存文件;看到 validate 失败时,会知道这是项目级问题。

常见失败与坑

最大的坑是把 pre-commit 做得太重。每次提交等待两分钟,团队很快就会学会绕过它。一个几秒钟完成的 hook 才可能成为习惯。

第二个坑是部分暂存。lint-staged 面向暂存区,但同一个文件里可能还有未暂存修改。排查时同时看 git status --shortgit diff --stagednpx lint-staged --debug

跨 Windows、macOS、Linux 的团队还要注意换行。Husky hook 是 shell 脚本,建议用 LF 保存。

* text=auto eol=lf
*.cmd text eol=crlf
*.bat text eol=crlf

另一个不该接受的修复是 || true。它会把失败吞掉,让质量门禁看起来存在、实际上失效。更好的处理是缩短错误输出,把重任务移到 pre-push,或在 README 中写清楚修复命令。

实际验证结果

我用一个小型 TypeScript/Vite 项目测试了这套配置,故意加入格式问题、未使用 import 和 MDX 空格问题。pre-commit 只处理暂存文件,所以速度保持在几秒级;npx lint-staged --debug 能清楚显示命中的文件和命令。类型错误没有放进 pre-commit,而是在 npm run validate 的 pre-push 阶段拦截,这样提交节奏更自然。

总结

Husky + lint-staged 是 Claude Code 工作流里的实用安全网。让 pre-commit 保持轻量,把重检查交给 pre-push 和 CI,并把这个分工写进给 Claude Code 的提示词。这样 hook 不会成为麻烦的仪式,而会变成团队共享的质量底线。

下一步可以继续完善 ESLint 配置,并用 Prettier 配置 统一格式策略。

#Claude Code #Husky #lint-staged #Git hooks #代码质量
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。