
lint-staged
在 Git 暂存区文件上运行 linter、formatter 等代码质量工具,确保每次提交都符合代码规范。
lint-staged 在 Git 暂存区文件上运行 linter、formatter 等代码质量工具,只对已暂存的文件执行检查,确保每次提交都符合规范,避免全量检查的性能开销。
lint-staged
在 Git 暂存区文件上运行 linter、formatter 等代码质量工具,确保每次提交都符合代码规范。
技术简介说明
lint-staged 是一个运行在 Git pre-commit 钩子中的 Node.js 工具,它只对 已暂存(staged)的文件 执行配置好的代码检查任务(如 ESLint、Prettier、Stylelint 等)。这样可以避免对整个仓库执行全量检查,大幅缩短提交前的等待时间。
lint-staged 本身不管理 Git 钩子,而是需要配合 Git 钩子管理工具(如 Husky 或 Lefthook)一起使用。当开发者执行 git commit 时,Git 触发 pre-commit 钩子 → Husky 调用 lint-staged → lint-staged 只检查被 git add 暂存的文件 → 检查通过后提交才能成功。
这种机制实现了 Fail Fast(快速失败)原则:将代码质量问题拦截在提交阶段,而非推送到 CI 后才发现。
基本信息
| 项目 | 信息 |
|---|---|
| 当前最新版本 | v17.0.8(2026年) |
| 许可证 | MIT |
| 语言/运行时 | Node.js(要求 ≥ 22.x) |
| Git 要求 | ≥ 2.32.0 |
| 包管理器 | npm / pnpm / yarn |
| GitHub 仓库 | lint-staged/lint-staged |
| npm 包 | lint-staged |
| 月下载量 | 数百万级别(前端生态基础设施) |
| 首次发布 | 2016 年 |
| 维护状态 | 积极维护中 |
快速上手
安装
# 使用 pnpm(推荐)
pnpm add -D lint-staged husky
# 使用 npm
npm install -D lint-staged husky
# 使用 yarn
yarn add -D lint-staged husky初始化 Husky
# 初始化 husky,创建 .husky/ 目录
npx husky init
# 这会自动创建 .husky/pre-commit 文件并添加 `npx lint-staged` 命令最小配置示例
在 package.json 中添加配置:
{
"lint-staged": {
"*.js": "eslint --fix",
"*.{js,ts,tsx}": "prettier --write"
}
}或者创建独立的配置文件 .lintstagedrc.js:
export default {
'*.js': ['eslint --fix'],
'*.{js,ts,tsx}': ['prettier --write'],
'*.{css,scss}': ['stylelint --fix'],
}完整最小示例
# 1. 安装依赖
pnpm add -D lint-staged husky eslint prettier
# 2. 初始化 husky
npx husky init
# 3. 确认 .husky/pre-commit 文件内容包含:
# npx lint-staged
# 4. 添加 lint-staged 配置到 package.json
# 5. 暂存文件并提交
git add .
git commit -m "feat: 初始化项目"
# → 此时 lint-staged 自动对暂存文件执行 eslint --fix 和 prettier --write核心概念与架构
工作流程
开发者修改文件
│
▼
git add <files> ← 文件进入暂存区(staging area)
│
▼
git commit
│
▼
Git 触发 pre-commit 钩子
│
▼
Husky 执行 .husky/pre-commit 脚本
│
▼
lint-staged 启动
│
├─→ 1. 获取所有暂存文件列表 (git diff --cached)
│
├─→ 2. 使用 glob 模式匹配暂存文件
│ (内部使用 picomatch 库)
│
├─→ 3. 对匹配的文件执行配置的命令
│ (如 eslint --fix file1.js file2.js)
│
├─→ 4. 将修改后的文件重新加入暂存区 (git add)
│
└─→ 5. 如果任一命令失败 → 提交被拒绝
如果全部通过 → 提交继续
Glob 匹配规则
lint-staged 使用 picomatch(v15+ 版本)进行 glob 匹配,遵循以下规则:
- 不含
/的 glob:匹配任意目录下的文件名。例如*.js匹配src/app.js和test/unit.js - 含
/的 glob:按完整路径匹配。例如src/*.js只匹配src/目录下的.js文件 - 支持扩展 glob:如
*.{js,ts}匹配.js和.ts文件
架构组成
| 模块 | 职责 |
|---|---|
| 配置加载器 | 读取 package.json、.lintstagedrc、.lintstagedrc.json、lint-staged.config.js 等配置 |
| Git 暂存文件获取 | 调用 git diff --cached --diff-filter=ACMR --name-only 获取暂存文件列表 |
| Glob 匹配引擎 | 使用 picomatch 将暂存文件与配置的 glob 模式匹配 |
| 任务执行器 | 顺序/并行执行配置的任务命令 |
| Git 操作管理 | 使用 git stash 暂存未暂存的变更,任务完成后恢复 |
| 输出格式化 | 控制台输出任务执行状态和结果 |
核心特性
1. 仅检查暂存文件
lint-staged 只对通过 git add 暂存的文件执行检查,而非整个仓库。这让提交前检查从全量 ESLint 的 30 秒缩短到仅检查几个文件的 1-2 秒。
2. 灵活的 Glob 模式匹配
支持丰富的 glob 语法,可为不同类型的文件配置不同的检查任务:
export default {
'*.js': 'eslint --fix',
'*.{ts,tsx}': ['eslint --fix', 'prettier --write'],
'*.md': 'markdownlint',
'src/**/*.{css,scss}': 'stylelint --fix',
}3. 函数式任务配置(v16+)
v16 引入的函数式任务,允许动态生成命令,接收匹配文件列表作为参数:
export default {
'*.js': (files) => {
// 根据文件数量选择不同的检查方式
if (files.length > 100) {
return ['eslint --fix --quiet']
}
return [`eslint --fix ${files.join(' ')}`]
},
}4. 多命令顺序执行
支持为同一 glob 模式配置多个命令,按数组顺序执行:
{
"*.js": ["eslint --fix", "prettier --write"]
}5. Git Stash 保护机制
lint-staged 在运行任务前会 git stash 保存未暂存的修改,任务完成后恢复。这确保了:
- 任务只看到暂存区的内容
- 未暂存的修改不会丢失
- 即使任务失败,原始工作状态也能恢复
6. 自动重新暂存
任务对文件做出修改后(如 --fix、--write),lint-staged 自动将修改后的文件重新加入暂存区,开发者无需手动操作。
7. 多种配置格式支持
package.json 中的 "lint-staged" 字段
.lintstagedrc(JSON)
.lintstagedrc.json
.lintstagedrc.yaml
.lintstagedrc.yml
.lintstagedrc.mjs
.lintstagedrc.js
.lintstagedrc.cjs
lint-staged.config.js
lint-staged.config.mjs
lint-staged.config.cjs
8. 详细的调试模式
使用 --debug 标志可以看到完整的执行过程,包括文件匹配、命令执行和性能计时信息:
npx lint-staged --debug9. 并发控制
可配置任务并发数,避免同时运行过多任务导致性能问题:
export default {
'*': 'prettier --write',
}
// 配合 --concurrent 参数控制并发npx lint-staged --concurrent 510. 相对路径支持
命令中的文件路径默认使用相对于项目根目录的路径,与 ESLint、Prettier 等工具的配置兼容。
生态图
与 Husky 的配合(行业标准)
┌──────────────────────────────────────────────────────────┐
│ Git Hooks 生态 │
├──────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌──────────────────┐ │
│ │ Husky │────▶│lint-staged│────▶│ ESLint/Prettier │ │
│ │(钩子管理) │ │(文件过滤) │ │ (代码检查工具) │ │
│ └─────────┘ └─────────┘ └──────────────────┘ │
│ │ │
│ ├──▶ commitlint(提交信息规范) │
│ │ │
│ └──▶ stylelint / markdownlint / ... │
│ │
└──────────────────────────────────────────────────────────┘
典型配置链路
Husky (pre-commit)
└─→ npx lint-staged
├─→ eslint --fix *.js
├─→ prettier --write *.{js,ts,tsx}
└─→ stylelint --fix *.css
Husky (commit-msg)
└─→ npx commitlint --edit "$1"
└─→ 校验提交信息格式
完整生态工具链
| 工具 | 角色 | 说明 |
|---|---|---|
| Husky | Git 钩子管理 | 管理 pre-commit、commit-msg 等钩子 |
| Lefthook | Git 钩子管理(替代) | Go 编写的 Husky 替代品,更快 |
| lint-staged | 暂存文件过滤执行 | 只运行 linter 到暂存文件上 |
| ESLint | JavaScript/TypeScript 检查 | 代码质量和风格检查 |
| Prettier | 代码格式化 | 统一代码风格 |
| Stylelint | CSS/SCSS 检查 | 样式代码质量检查 |
| commitlint | 提交信息规范 | 配合 commit-msg 钩子使用 |
| Biome | 全能工具(新兴) | Rust 编写的 linter + formatter |
| Oxlint | JavaScript 检查(新兴) | Rust 编写的超快 linter |
适用场景
1. 团队代码规范统一
在多人协作项目中,通过 lint-staged 确保每次提交都经过 ESLint 和 Prettier 处理,防止不规范的代码进入仓库。
// .lintstagedrc.js
export default {
'*.{js,ts,tsx}': ['eslint --fix', 'prettier --write'],
}2. 增量格式化与修复
对已有存量代码的老项目,lint-staged 允许逐步修复 —— 只格式化本次修改的文件,而不必一次性处理整个仓库。
export default {
'*.js': ['eslint --fix --quiet'], // --quiet 减少输出干扰
}3. Monorepo 场景
在 pnpm workspace / Turborepo / Nx 等 Monorepo 中,lint-staged 配合工作区工具,只检查变更的包中的文件。
// 根目录 .lintstagedrc.js
export default {
'packages/**/*.{js,ts}': ['pnpm --filter ./packages/* exec eslint --fix'],
}4. 多语言/多类型文件项目
对同时包含 JavaScript、TypeScript、CSS、Markdown 等多种文件类型的项目,按文件类型分别配置检查工具。
export default {
'*.{js,ts,tsx}': ['eslint --fix', 'prettier --write'],
'*.{css,scss,less}': ['stylelint --fix', 'prettier --write'],
'*.md': ['markdownlint', 'prettier --write'],
'*.{json,yaml,yml}': ['prettier --write'],
}5. CI 前的本地质量门禁
作为开发者提交代码的第一道防线,将 CI 中可能失败的检查提前到本地执行,减少 CI 资源浪费。
6. 自动化代码修复工作流
结合 --fix 和 --write 参数,lint-staged 在提交前自动修复可自动处理的问题(如缺少分号、引号风格等)。
export default {
'*.{js,ts}': [
'eslint --fix --max-warnings=0',
'prettier --write',
],
}7. 安全扫描前置
对暂存的代码运行安全扫描工具,防止敏感信息泄露到 Git 历史中。
export default {
'*': ['npx gitleaks protect --staged --verbose'],
}开发与工程化
配置文件选型
| 配置方式 | 适用场景 | 示例 |
|---|---|---|
package.json "lint-staged" | 简单项目、配置简短 | {"*.js": "eslint"} |
.lintstagedrc.js | 需要条件逻辑或函数式任务 | export default { ... } |
lint-staged.config.js | 配置复杂、需要导入其他模块 | 独立配置文件 |
.lintstagedrc.json | 纯 JSON、团队协作 | 标准 JSON 配置 |
与 Husky 的完整集成
# 目录结构
├── .husky/
│ ├── pre-commit # 内容: npx lint-staged
│ └── commit-msg # 内容: npx commitlint --edit "$1"
├── package.json
└── .lintstagedrc.js.husky/pre-commit 文件内容:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged调试技巧
# 启用详细日志
npx lint-staged --debug
# 查看匹配的文件(不执行命令)
npx lint-staged --diff
# 使用相对路径调试
npx lint-staged --relative在 Monorepo 中的工程化
monorepo/
├── .husky/
│ └── pre-commit # npx lint-staged
├── .lintstagedrc.js # 根目录统一配置
├── packages/
│ ├── ui/
│ │ └── .eslintrc.js # 各包独立配置
│ └── app/
│ └── .eslintrc.js
└── package.json
根目录 .lintstagedrc.js:
export default {
'packages/**/*.{js,ts,tsx}': (files) => {
// 按包分组执行,避免重复初始化
const packages = new Set(
files.map(f => f.match(/^packages\/([^/]+)/)?.[1]).filter(Boolean)
)
const commands = []
for (const pkg of packages) {
commands.push(`pnpm --filter ./${pkg} exec eslint --fix`)
}
return commands
},
}性能与安全
性能考量
| 因素 | 影响 | 优化建议 |
|---|---|---|
| 暂存文件数量 | 文件越多越慢 | lint-staged 只处理暂存文件,通常很快 |
| 命令初始化时间 | ESLint 配置复杂时初始化慢 | 考虑使用 Oxlint/Biome 替代 |
| Git stash 操作 | 大仓库可能较慢 | 升级到 Git ≥ 2.32.0 |
| 命令串行执行 | 多个命令逐个执行 | 使用 --concurrent 控制并发 |
性能优化建议:
# 使用 Biome 替代 ESLint + Prettier(15x 更快)
{
'*.{js,ts,tsx}': 'biome check --apply'
}
# 使用 --quiet 减少输出
{
'*.js': 'eslint --fix --quiet'
}安全考量
| 方面 | 说明 |
|---|---|
| 依赖安全 | lint-staged 本身无已知严重漏洞,Snyk 显示健康状态 |
| 命令注入风险 | glob 匹配的文件名直接作为命令参数,特殊文件名可能导致问题 |
| Snap 沙箱兼容 | v17 修复了 Snap 安装 Node.js 的沙箱限制问题 |
| Git 版本要求 | v17 起要求 Git ≥ 2.32.0,确保兼容性 |
| 敏感信息泄露 | 建议配合 gitleaks 等工具扫描暂存文件中的密钥 |
依赖关系
lint-staged 的核心依赖:
lint-staged
├── picomatch # Glob 匹配
├── execa # 子进程执行
├── lilconfig # 配置文件查找
├── chalk # 终端彩色输出
├── commander # CLI 参数解析
├── debug # 调试日志
└── yaml # YAML 配置解析
技术对比
lint-staged vs Lefthook
| 维度 | lint-staged | Lefthook |
|---|---|---|
| 语言 | Node.js | Go(单二进制文件) |
| 职责 | 仅处理暂存文件过滤与执行 | 完整的 Git 钩子管理 + 文件过滤 |
| 是否需要配合 Husky | ✅ 是 | ❌ 否(自身管理钩子) |
| 启动速度 | 需要 Node.js 运行时 | 无运行时开销,毫秒级启动 |
| 并行执行 | ❌ 顺序执行 | ✅ 原生并行 |
| 配置格式 | JSON/JS/YAML | YAML |
| 生态成熟度 | ⭐⭐⭐⭐⭐ 行业标准 | ⭐⭐⭐⭐ 快速增长 |
| 适合场景 | Node.js 项目、标准前端栈 | 大型 Monorepo、追求极致性能 |
lint-staged vs pre-commit (Python)
| 维度 | lint-staged | pre-commit (Python) |
|---|---|---|
| 语言 | Node.js | Python |
| 平台 | Node.js 生态 | 语言无关 |
| 文件过滤 | 内置 glob 匹配 | 内置 hooks 类型过滤 |
| 安装方式 | npm install | pip install pre-commit |
| 配置 | package.json / .lintstagedrc | .pre-commit-config.yaml |
| 适用项目 | 前端/Node.js 项目 | 多语言项目 |
lint-staged vs Husky(常见误解)
lint-staged 和 Husky 不是竞争关系,而是互补关系。
| 职责 | Husky | lint-staged |
|---|---|---|
| 管理 Git 钩子 | ✅ 是 | ❌ 否 |
| 过滤暂存文件 | ❌ 否 | ✅ 是 |
| 执行代码检查 | ❌ 否(调用其他工具) | ✅ 是 |
| 工作层级 | Git 钩子层 | 文件过滤与任务执行层 |
Husky 负责在 git commit 时触发钩子 → lint-staged 在钩子中执行,只检查暂存文件。
选型建议
小型项目 / 标准前端项目 → Husky + lint-staged(行业标准)
大型 Monorepo / 追求极致性能 → Lefthook(替代 Husky + lint-staged)
多语言项目 → pre-commit (Python)
追求极致速度(Rust 工具链) → Biome / Oxlint + 手动 Git hooks
最佳实践
1. 保持配置简洁
// ✅ 推荐:简洁清晰
export default {
'*.{js,ts,tsx}': ['eslint --fix', 'prettier --write'],
'*.{css,scss}': ['stylelint --fix', 'prettier --write'],
}
// ❌ 避免:过于复杂的逻辑
export default {
'*': (files) => {
// 数百行复杂逻辑...
}
}2. 使用 --fix 自动修复
export default {
// ✅ 自动修复 + 格式化
'*.{js,ts}': ['eslint --fix', 'prettier --write'],
// ❌ 只检查不修复,发现问题后提交被拒,开发者还得手动修
'*.{js,ts}': ['eslint'],
}3. 命令顺序:先修复后格式化
export default {
// ✅ 先 eslint 修复,再 prettier 格式化
'*.js': ['eslint --fix', 'prettier --write'],
// ❌ 顺序反了,eslint 修复可能会破坏 prettier 格式
'*.js': ['prettier --write', 'eslint --fix'],
}4. 搭配 commitlint 校验提交信息
.husky/commit-msg:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx commitlint --edit "$1"5. 处理特殊文件路径
export default {
// 使用函数式任务处理需要特殊逻辑的场景
'*.js': (files) => {
// 排除测试文件
const sourceFiles = files.filter(f => !f.includes('.test.'))
return [`eslint --fix ${sourceFiles.join(' ')}`]
},
}6. 使用 --max-warnings 控制质量
export default {
// 有 warning 也不允许提交
'*.js': 'eslint --fix --max-warnings=0',
}7. CI 中也运行 lint-staged
# .github/workflows/ci.yml
- name: Run lint-staged
run: npx lint-staged --diff=origin/${{ github.base_ref }}8. 版本锁定
将 lint-staged 安装为 devDependency 而非全局工具,确保团队使用相同版本。
技术局限与边界
已知局限
| 局限 | 说明 | 应对策略 |
|---|---|---|
| Node.js 运行时开销 | 每次提交需启动 Node.js,Lefthook(Go)更快 | 对速度敏感的项目考虑 Lefthook |
| 无法并行执行命令 | 多个命令按顺序执行 | 使用 Biome 替代多个工具,减少命令数 |
| 大仓库性能 | Git 操作(stash、diff)在大仓库中较慢 | 使用 shallow clone、稀疏 checkout |
| Monorepo 复杂性 | 跨包依赖检查难以精确处理 | 配合 Turborepo/Nx 的增量能力 |
| 无法检查类型错误 | TypeScript 类型检查通常需要项目上下文 | 类型检查放 CI,lint-staged 只做语法检查 |
| Git stash 恢复风险 | 极端情况下(如进程被杀)stash 可能恢复失败 | lint-staged 有备份机制,但仍建议勤提交 |
| Windows 兼容性 | 部分场景下路径处理有问题 | 使用正斜杠路径、测试 Windows 环境 |
何时不该用 lint-staged
- 纯后端项目(无 Node.js 环境):考虑
pre-commit(Python)或lefthook - 极小的脚本项目:增加工具链负担大于收益
- 已有完善 CI 检查的单人项目:可选,但非必须
- 非 Git 项目:lint-staged 依赖 Git 暂存区
学习资源
官方资源
- lint-staged GitHub 仓库 — 源码、Issues、Release Notes
- lint-staged npm 包 — 包信息与版本历史
- MIGRATION.md — 版本迁移指南
- lint-staged 中文网 — 中文开发文档
优质教程
- Prevent Bad Commits with Husky and lint-staged — Better Stack 2025 年完整指南
- Git Hooks with Husky and lint-staged: Complete Setup Guide — DEV Community 2025 指南
- Diving into Husky and Lint-staged — 深入原理分析
- Husky and lint-staged — Enterprise UI — Steve Kinney 企业级 UI 课程
中文资源
- lint-staged 使用指南 — 稀土掘金 — 详细使用教程
- husky 与 lint-staged 详解 — 稀土掘金 — 项目规范入门
- 详解代码提交规范 — 稀土掘金 — lint-staged + commitlint 组合
- husky vs lefthook 对比 — 知乎 — 新一代 Git Hooks 工具对比
对比与趋势
- husky vs lefthook vs lint-staged 2026 — PkgPulse — 2026 年工具对比
- Lefthook vs Husky: Why I Switched — 从 Husky 迁移到 Lefthook 的经验
- Pre-commit Hooks 15× Faster — Biome vs ESLint — 性能优化案例分析
2026 年现状
版本动态
- 最新版本 v17.0.8(2026年),要求 Node.js ≥ 22、Git ≥ 2.32.0
- v17 引入了 npm staged publishing(分阶段发布)机制
- 项目使用 Changesets 管理版本和发布流程
- 持续活跃维护,CI 流水线已适配 Windows 2025/2026 运行环境
生态地位
lint-staged + Husky 在 2026 年仍然是前端项目的 行业标准配置,被绝大多数 Next.js、Vite、Create React App 等脚手架默认集成或推荐。
竞争趋势
- Lefthook(Go 编写)作为一体化替代方案增长迅速,适合追求性能的大型项目
- Biome(Rust 编写)作为 ESLint + Prettier 的替代,将 lint-staged 的任务执行时间缩短 15 倍
- Oxlint(Rust 编写)提供极速 JavaScript 检查能力
- hk(jdx)新工具,强调原生并行执行 linter
选型建议(2026)
标准前端项目(中小型) → Husky + lint-staged(不变的首选)
大型 Monorepo → Lefthook(替代 Husky + lint-staged)
追求极致开发体验 → Biome/Oxlint + lint-staged 或 Lefthook
全栈/多语言项目 → Lefthook 或 pre-commit (Python)
lint-staged 的核心价值 —— "只对暂存文件运行检查" —— 在 2026 年依然不可替代。即使底层工具(ESLint → Oxlint、Prettier → Biome)在更迭,lint-staged 作为暂存文件过滤层的定位依然稳固。