Lefthook 配置在 monorepo 中怎么让子项目复用根目录钩子
来源:17golang原创
时间:2026-11-05 12:43:39 238浏览 收藏
在 monorepo 里,Git 仓库只有一个根目录,但 frontend、backend、tools 往往各自有 package.json、Gemfile 或独立的检查命令。Lefthook 的稳定做法是:把 Git 钩子安装在仓库根目录,根配置用 extends 汇总子项目配置,再给每个子项目任务设置自己的 root 和文件匹配规则。这样提交入口只有一套,命令却不会跑错目录。
官方地址:https://github.com/evilmartians/lefthook
不要在每个子目录重复安装 Lefthook。根目录保留唯一主配置,子项目只提供可合并的任务定义;执行目录交给 root: "frontend/" 这类任务级配置,文件过滤仍然按照 Git 仓库根目录计算。
先把目录和职责分开
假设仓库结构如下,两个应用共用一次 pre-commit,但检查器不能互相读取对方的依赖目录:
monorepo/
├── lefthook.yml
├── frontend/
│ ├── package.json
│ └── src/
├── backend/
│ ├── pyproject.toml
│ └── app/
└── tools/
└── scripts/
这里有三个容易混淆的概念:
lefthook.yml是根目录的入口,负责把配置组装起来;root改变具体任务执行时的当前工作目录;glob仍从实际 Git 根目录匹配路径,不能把它理解成“先进入 root 再从零开始匹配”。
如果你把 frontend 和 backend 初始化成两个完全独立的 Git 仓库,这套方案就不再是本文讨论的范围;本文只针对一个 Git 根目录下的多个子项目。
在根目录登记唯一的 Lefthook 入口
操作路径是“项目根目录 → 新建 lefthook.yml → 写入 extends”。根配置不承担所有命令细节,只负责把子项目配置纳入同一套钩子。
# 这行注释说明配置入口只放在 Git 仓库根目录 extends: # 让前端任务从自己的配置文件维护 - frontend/lefthook.yml # 让后端任务保持与前端相同的提交入口 - backend/lefthook.yml pre-commit: # 根层只负责统一调度,具体任务由 extends 文件提供 parallel: true
可见状态应当是:根目录存在一个主配置,子项目文件只作为被合并的配置来源。Lefthook 官方说明中,extends 的内容会合并到主配置;如果多个任务希望在合并时被识别为同一个任务,给它们稳定的 name 会比依赖数组位置更容易维护。

在子项目文件里设置 root 和任务
操作路径是“frontend → lefthook.yml → pre-commit.jobs → 设置 root、glob、run”。下面的配置把前端与后端拆成两个命名任务,并让命令在各自目录里执行:
# frontend/lefthook.yml:命令在 frontend/ 下执行
pre-commit:
jobs:
- name: frontend-lint
# 注意保留末尾斜杠,避免路径拼接出现歧义
root: "frontend/"
# glob 仍按 Git 根目录匹配,所以这里写 frontend 下的相对路径
glob: "frontend/**/*.{js,ts,tsx}"
# staged_files 会把匹配到的暂存文件交给前端脚本
run: npm run lint -- {staged_files}
# backend/lefthook.yml:命令在 backend/ 下执行
pre-commit:
jobs:
- name: backend-check
# Python 工具读取 backend/ 下的 pyproject.toml
root: "backend/"
# 只筛选后端源码,避免前端提交触发后端检查
glob: "backend/**/*.py"
# 这里使用仓库根目录传入的文件路径,命令仍在 backend/ 中启动
run: python -m ruff check {staged_files}
这里最容易出现的误区是把 glob 写成 "src/**/*.{js,ts}"。当 Lefthook 从仓库根目录计算暂存文件时,frontend 的任务应写成 "frontend/src/**/*.{js,ts}";而命令的当前目录由 root: "frontend/" 决定。两个字段解决的是不同问题。
如果你使用的是嵌套任务组,可以把共同的 root、glob、env 或 files 放到 group 上,让组内任务继承;需要被 extends 或本地配置稳定合并的组,也应设置名称。
把钩子安装到根目录并查看合并结果
操作路径是“项目根目录 → Lefthook 命令 → install → dump”。这一步先安装一次根钩子,再查看 Lefthook 实际使用的合并配置:
# 在 monorepo 根目录执行,确保 Git 根和配置入口一致 lefthook install # 输出 main config、extends 和 local config 合并后的实际配置 lefthook dump # 手动运行一次提交钩子,观察哪些任务被匹配 lefthook run pre-commit
界面或命令输出里应能看到 frontend-lint 与 backend-check 两个命名任务。提交只改了 frontend/src/App.tsx 时,前端任务应保留,后端任务应因 glob 没有匹配文件而跳过;反过来修改 backend/app/main.py 也是同理。

路径匹配为空时怎么判断
遇到任务显示跳过,不要先把 root 改成仓库根目录。按下面的顺序看最省时间:
- 先确认文件已经暂存,因为
{staged_files}只代表当前提交候选文件。 - 再比较
glob与 Git 根目录的相对路径,例如frontend/src/index.ts是否真的带有frontend/前缀。 - 最后确认
root以目录形式书写,并且命令需要的 package 或配置文件确实存在于该目录。
# 把目标文件加入暂存区,模拟一次前端提交候选 git add frontend/src/index.ts # 只运行提交钩子,不创建提交,便于查看匹配和工作目录 lefthook run pre-commit
如果 dump 里任务存在但运行时为空,通常是文件没有暂存,或者 glob 少写了子项目目录。若任务能匹配到文件但命令报找不到 package,通常是 root 写错;此时修正执行目录,而不是扩大 glob。
常见配置误区
每个子项目都执行一次 lefthook install
在一个 Git 仓库中重复安装会让维护者误以为每个子项目都是独立入口。把安装动作固定在根目录,子项目只维护被 extends 的配置即可。
把 root 当成 glob 的起点
root 是命令工作目录和路径过滤边界,官方文档明确说明 glob 仍按 Git 仓库真实根目录计算。只要理解这一点,绝大多数“任务为什么跳过”都能直接定位。
直接复制整段 pre-commit 而不命名任务
配置拆分后,多个文件可能同时定义同一个钩子。给具体 job 或 group 写上稳定的 name,再用 dump 查看最终合并结果,后续覆盖和扩展会更可控。
最后确认这套结构是否适合你的仓库
如果你的目标是“一个 Git 仓库、一套根钩子、多个子项目各自运行检查”,推荐保留下面的最小结构:
monorepo/ ├── lefthook.yml # 唯一入口:extends 子项目配置 ├── frontend/lefthook.yml # root: frontend/,glob: frontend/** └── backend/lefthook.yml # root: backend/,glob: backend/**
安装时只在根目录运行 lefthook install,排查时先运行 lefthook dump,执行目录看 root,文件范围看 glob。这四个动作能把“钩子没有触发”“命令读错配置”和“子项目互相干扰”拆成三个独立问题处理。
官方文档入口:https://lefthook.dev/configuration/
-
474 收藏
-
381 收藏
-
164 收藏
-
182 收藏
-
203 收藏
-
498 收藏
-
302 收藏
-
186 收藏
-
327 收藏
-
249 收藏
-
463 收藏
-
144 收藏
-
416 收藏
-
326 收藏
-
145 收藏
-
227 收藏
-
309 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习