告别扯皮!用 Git Hooks + lint-staged 打造团队代码风格的自动“守门员”
你是不是也受够了在 Code Review 里争论缩进是两格还是四格?行尾要不要加分号?每次提交前都要手动跑一遍格式化命令也太反人类了。
是时候把这些琐事交给机器了。今天手把手带你搭建一个基于 Git Hooks 的自动化代码检查和格式化流程,让不符合规范的代码根本无法进入仓库,从根源上保证团队代码的一致性。
🛠️ 我们的武器库
这套方案的核心是几个精巧的工具组合:
- Husky:现代化地管理 Git Hooks。它让你能像在
package.json里配置脚本一样轻松定义钩子行为,解决了原生 hooks 难以同步给团队成员的问题。 - lint-staged:“利器”。它只对
git add后暂存区(staged)的文件运行指定的命令,快如闪电⚡。让你没必要每次都对整个项目进行 linting。 - Prettier & ESLint :分别负责代码格式化(风格)和静态检查(质量问题)。Prettier “专断独行”,但能消除所有风格争论;ESLint 灵活可配置,捕捉潜在错误。
🚀 四步搭建自动化流水线
假设我们有一个 Node.js 项目。
Step 1: 安装依赖
npm install --save-dev husky lint-staged prettier eslint
# 或者用 yarn / pnpm
Step 2: 启用 Husky
现代版本的 Husky (v7+) 安装后会自动完成初始化。通常你只需要执行:
npx husky-init && npm install
这个命令会做三件事:
- 在
package.json中添加一个准备脚本"prepare": "husky install"。 - 创建
.husky目录(这里就是存放我们钩子脚本的地方)。 - 在
.husky/pre-commit中生成一个示例钩子文件。
现在,Husky 已经接管了你项目的 Git Hooks。.husky 目录是可以提交到版本库的!
Step 3: 配置 lint-staged
在 package.json (或单独的 .lintstagedrc.js等文件)中添加配置:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix", // ESLint自动修复
"prettier --write" // Prettier格式化
],
"*.{css,scss,less,md,json}": [
"prettier --write"
]
}
}
这个配置的意思是:
- 对于暂存区的 JS/TS 等文件,先跑 ESLint 修复问题,再用 Prettier 统一格式化。
- 对于样式文件、Markdown、JSON等,直接用 Prettier格式化。
Step 4: “焊接” Husky 与 lint-staged
修改 .husky/pre-commit 这个钩子文件:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
搞定!现在当你执行 git commit时,会触发以下链条:git commit → Husky(pre-commit) → npx lint-staged → lint-staged读取配置 → 仅对暂存文件依次执行 ESLint & Prettier → (如果全部通过)→ Commit成功;(如果检查出错或格式化有冲突)→ Commit中止。
🔧 Why & How It Works?
Q: .git/hooks里的钩子不是不能共享吗?
A: Bingo!这是原生Hook的最大痛点。Husky的方案是在.git/hooks里安装一个通用的“代理”,这个代理会去执行项目目录下.husky/里的对应脚本(比如pre-commit)。而.husky/目录是可以随项目一起提交的!新成员克隆项目后运行一次 npm install (会触发prepare脚本),就自动完成了Hook的安装。
Q: pre-commit vs pre-push?
A: pre-commit更快反馈,“脏”代码不会进本地历史;pre-push允许你在本地自由Commit(比如WIP),但在分享给他人前做最终检查。我们一般选pre-commit来保证每个提交点都是干净的。(注:你可以在.husky/pre-push里添加单元测试等更耗时的检查)。
Q: ESLint和Prettier冲突怎么办?
A: ESLint主要负责代码质量规则(如未使用的变量),Prettier负责风格(空格、换行)。使用 eslint-config-prettier来关闭ESLint中所有与格式相关的规则,让Prettier接管即可。
📈 进阶技巧与避坑指南
指定配置文件路径
如果你的配置文件不在根目录:{ "lint-staged": { "*.js": ["prettier --write --config ./path/to/.prettierrc"] } }跳过Hook提交
偶尔需要绕过检查(慎用):git commit -m \"紧急fix\" --no-verify # or -n只对新增文件生效?
可以在Hook脚本里结合git diff --cached --name-only --diff-filter=A来识别新增文件并应用特殊规则(例如必须添加版权声明)。支持Monorepo?
在根项目的package.json中配置husky和lint-staged即可作用于所有子包。
✨ One More Thing
真正的工程化不止于此。你可以将这个流程扩展:
.
个人习惯是把项目的这套配置固化成一个脚手架或模板仓库。新项目初始化时一键拥有完整的代码风格守护能力。“工欲善其事必先利其器”,把时间浪费在和机器较劲上不值得。