人人都会AI编程

23.3 代码提交规范:Husky + lint-staged + commitlint

更新时间:2026-07-11

上一节讲了代码格式化和静态检查,但工具再强大,如果开发团队不遵守,依然形同虚设。最可靠的方案是把规则嵌入到代码提交流程中,让不规范的代码根本进不了仓库。Huskylint-stagedcommitlint 就是为此而生的“提交门禁”工具。

23.3.1 三者分工

  • Husky:在 Git 钩子(hook)执行自定义命令,比如在 pre-commit 时运行检查,在 commit-msg 时校验提交信息。
  • lint-staged:只对 Git 暂存区中的文件执行检查,避免每次提交都扫描整个项目,极大提升检查速度。
  • commitlint:校验 git commit message 是否符合约定的规范,确保提交历史可读、可追溯。

三者的协作流程通常是:

开发者执行 git commit → Husky 触发 pre-commit 钩子 → lint-staged 对暂存文件执行 ESLint/Prettier 检查 → 检查通过后进入 commit-msg 钩子 → commitlint 校验提交信息格式 → 全部通过后提交成功。

23.3.2 配置实战

以 npm 项目为例,假设项目已经安装了 ESLint 和 Prettier。

1. 安装依赖

npm install --save-dev husky lint-staged @commitlint/cli @commitlint/config-conventional

2. 初始化 Husky

如果使用的是 Husky v9+:

npx husky init

这会在项目根目录创建 .husky/ 目录,并自动添加 pre-commit 钩子文件。如果没有自动创建,可以手动添加:

npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg  "npx --no -- commitlint --edit \$1"

注意\$1 是传递给钩子脚本的 commit message 临时文件路径,必须原样保留。

3. 配置 lint-staged

package.json 或单独的 lint-staged.config.js 中定义规则:

{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.{css,scss,less,md,json}": ["prettier --write"]
  }
}

含义:对暂存区中匹配的文件,先运行 ESLint 自动修复,再用 Prettier 格式化。

4. 配置 commitlint

在项目根目录创建 commitlint.config.js

module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    // 自定义规则,例如限制 header 最大长度
    'header-max-length': [2, 'always', 72],
  },
};

这套“conventional”规范源自 Angular 提交规范,格式为:

<type>(<scope>): <short summary>

常用 type 包括:

  • feat:新功能
  • fix:修复 bug
  • docs:文档变更
  • style:代码格式(不影响功能)
  • refactor:重构
  • test:添加或修改测试
  • chore:构建或辅助工具的变动

示例:feat(auth): add login with JWT

23.3.3 实际效果

配置完成后,开发者的体验是这样的:

$ git add .
$ git commit -m "fixed bug"
  • 第一步,Husky 触发 pre-commit,lint-staged 自动对暂存文件执行 ESLint 和 Prettier。如果有问题,会自动修复或报错退出,阻止提交。
  • 如果 lint-staged 通过,进入 commit-msg 钩子,commitlint 检查提交信息格式。"fixed bug" 因缺少 type: 前缀被视为非法,提交会被拒绝,并给出错误提示。
  • 开发者需修改提交信息为 fix: fix user login error,重新提交才能成功。

23.3.4 这样做的实际价值

  • 防止漏网之鱼:即使开发者忘记在本地运行 lint,代码在提交那一刻也会被强制检查,确保进入仓库的代码都是格式整洁、通过静态分析的。
  • 保障提交历史可读:统一的提交格式让 git log 清晰明了,自动生成 CHANGELOG 和版本管理都变得更可靠。
  • 提升团队协作效率:新人入职后只需配置好本地的 Git 钩子(或依赖团队脚手架),无需记住所有检查命令,工具会自动把关。
  • 只检需检查的文件:lint-staged 只扫描暂存区文件,避免了全量检查的时间开销,让提交过程依然快速。

23.3.5 常见问题与解决

1. 跳过钩子怎么办?

Git 允许用 --no-verify 强制跳过钩子:

git commit -m "emergency fix" --no-verify

原则上不能完全杜绝这种行为,但可以通过 CI/CD 在远端再做一次相同的检查。如果团队成员普遍依赖跳过,说明本地钩子配置体验不佳(如速度太慢),需要优化规则。

2. lint-staged 执行失败但代码已被格式化?

lint-staged 会优先执行 --fix,修复后的文件会被重新添加回暂存区。如果 ESLint 报告了无法自动修复的错误(如未使用的变量禁止删除),lint-staged 会返回非零退出码,阻止提交。这是预期行为,开发者需要手动修复后重新提交。

3. Windows 兼容问题

Husky 在不同操作系统下需要确保 shell 脚本可执行,通常通过 Git Bash 或 WSL 解决。使用 Husky v9+ 默认会处理好跨平台问题。如果遇到“权限不足”错误,可以尝试:

chmod +x .husky/pre-commit

23.3.6 小结

Husky + lint-staged + commitlint 组合是当前前端工程化中最主流的提交门禁方案。它们不需要昂贵的 CI 资源,在开发者本地就能完成最基本的代码质量把关,与 ESLint、Prettier 形成完整的“写 → 检 → 修 → 拦”闭环。善用这套工具,等于给项目团队加了一道低成本、高回报的质量防线。