lefthook 配置文件完全指南:命名规则、加载顺序与顶层配置项解析
2026/9/16 22:47:56 网站建设 项目流程

lefthook 配置文件完全指南:命名规则、加载顺序与顶层配置项解析

【免费下载链接】lefthookFast and powerful Git hooks manager for any type of projects.项目地址: https://gitcode.com/GitHub_Trending/le/lefthook

lefthook 是一款快速且强大的 Git hooks 管理器,其一切行为都由项目根目录下的配置文件驱动。本文以 docs/configuration.md 为主线,系统讲解 lefthook 主配置文件的合法命名与格式、lefthook-local本地配置合并机制、配置的加载与覆盖顺序,以及全部顶层配置项(min_versionextendsremotessource_diroutputrclefthook等)和 Git hook 内部结构(commands/scripts/jobs)的用法。读完本文,你将能写出规范、可维护、可跨项目复用的 lefthook 配置,并理解底层加载器的工作方式。

配置文件名称与支持格式

lefthook 的主配置文件支持 YAML、TOML、JSON、JSONC 四种格式,每种格式都有多个可接受的命名。官方支持的完整清单如下:

格式可接受的配置文件名
YAMLlefthook.ymllefthook.yaml.lefthook.yml.lefthook.yaml.config/lefthook.yml.config/lefthook.yaml
TOMLlefthook.toml.lefthook.toml.config/lefthook.toml
JSONlefthook.json.lefthook.json.config/lefthook.json
JSONClefthook.jsonc.lefthook.jsonc.config/lefthook.jsonc

几点重要约定:

  • 一个项目只使用一种格式。如果项目中同时存在多个配置文件,lefthook 只会使用其中的某一个,而且你无法确定最终加载的是哪一个(实际取决于加载顺序)。因此在团队中务必统一格式,避免歧义。
  • 无前导点的文件名也会在.config子目录中查找。例如lefthook.yml会被解析为lefthook.yml.config/lefthook.yml两种可能位置。
  • 从源码看,加载器在 internal/config/loader.go 中按扩展名顺序[]string{".yml", ".yaml", ".json", ".jsonc", ".toml"}遍历,并为每个扩展名依次尝试lefthook.lefthook.config/lefthook三种基础名称(MainConfigNames),找到第一个存在的文件即加载并停止。

lefthook-local:本地私有配置的合并机制

除了主配置文件,lefthook 还会额外合并一个名为lefthook-local的配置文件。它适用于同样的四种格式:

  • lefthook-local.yml/lefthook-local.yaml/.lefthook-local.yml/.lefthook-local.yaml/.config/lefthook-local.yml/.config/lefthook-local.yaml
  • lefthook-local.toml/.lefthook-local.toml/.config/lefthook-local.toml
  • lefthook-local.json/.lefthook-local.json/.config/lefthook-local.json
  • lefthook-local.jsonc/.lefthook-local.jsonc/.config/lefthook-local.jsonc

命名规则与主配置一一对应:如果主配置使用前导点命名(如.lefthook.json),那么本地配置也必须使用前导点命名(.lefthook-local.json)。源码中LocalConfigNames[]string{"lefthook-local", ".lefthook-local", ".config/lefthook-local"}(见 internal/config/loader.go)。

lefthook-local可以独立存在,即使没有主配置文件也能使用。这是它的核心使用场景:当你想在本地单独启用 lefthook、而不把配置强加给队友时,只需创建一个lefthook-local.yml并把它加入全局.gitignore即可——它不会进入版本库,也不会影响其他开发者的环境。

合并优先级

lefthook 配置的覆盖顺序(从低到高)为:

  1. lefthook.yml—— 主配置文件
  2. extends—— 通过extends选项引入的配置
  3. remotes—— 通过remotes选项下载的远程配置
  4. lefthook-local.yml—— 本地配置文件,可以覆盖以上所有设置

从源码看,loader.go 的LoadKoanf先加载主配置(loadMain),再通过LoadSecondary加载extendsremotes与本地配置,最后在unmarshalConfigs中执行main.Merge(secondary)(见 loader.go)完成合并。钩子(hook)级别的合并是逐个进行的:addHook将本地配置中同名 hook 的内容合并到主配置的 hook 上(见 loader.go)。这也解释了为什么本地配置最适合存放"个人专属"的 lint 参数、rc路径或调试开关。

顶层配置项总览

lefthook 的配置结构由 internal/config/config.go 中的Config结构体定义。顶层可配置项如下(完整说明见 docs/configuration/README.md):

配置项说明
assert_lefthook_installed断言 lefthook 已正确安装
colors开启/关闭或自定义输出颜色
extends引入其他配置文件进行合并
lefthook指定 lefthook 可执行文件路径或运行命令
min_version指定 lefthook 二进制的最低版本
no_tty隐藏 spinner 等交互元素
output控制输出内容的详细程度
rc提供一个 rc 文件(简单的 sh 脚本)
remotes从远程仓库拉取并合并共享配置
source_dir更改脚本文件目录(默认.lefthook/
source_dir_local更改本地脚本文件目录(默认.lefthook-local/
skip_lfs跳过运行 Git LFS hooks(默认开启)
templates为 run 命令中的替换提供自定义模板
{Git hook name}任意 Git hook 的配置,如pre-commit

min_version

如果你想强制使用某个最低版本的 lefthook(例如需要旧版本不具备的特性),可以设置min_version

# lefthook.yml min_version: 1.1.3

当本机 lefthook 版本低于该值时,命令会直接报错退出,从而避免因版本不一致导致的配置解析失败。

lefthook

默认值:null(自 lefthook1.10.5起提供)

提供一个 lefthook 可执行文件的完整路径,或一条运行 lefthook 的命令,支持 Bourne shell(sh)语法。设置它的典型场景有三种:

  1. 强制使用依赖中特定版本的 lefthook(如 npm 包自带的二进制);
  2. 项目使用 PnP loader,且包含 lefthook 依赖的package.json位于子目录;
  3. 想在lefthook-local.yml中固定本机 lefthook 的可执行路径。
# lefthook.yml —— 指定可执行文件路径 lefthook: /usr/bin/lefthook pre-commit: jobs: - run: yarn lint
# lefthook.yml —— 指定运行命令(支持多行 sh 语法) lefthook: | cd project-with-lefthook pnpm lefthook pre-commit: jobs: - run: yarn lint root: project-with-lefthook
# lefthook.yml —— 强制使用 Rubygems 提供的版本 lefthook: bundle exec lefthook pre-commit: jobs: - run: bundle exec rubocop -- {staged_files}
# lefthook-local.yml —— 开启调试日志 lefthook: LEFTHOOK_VERBOSE=1 lefthook

注意:出于安全原因,lefthook选项不会remotesextends中合并,但会从lefthook-local.yml中合并。

extends

你可以通过extends用一个或多个 YAML 文件扩展当前配置,其内容会被合并进来。lefthook.ymllefthook-local.ymlremotes配置的 extends 是分开处理的,因此这些文件可以有不同的 extends。路径支持通配符*

# lefthook.yml extends: - /home/user/work/lefthook-extend.yml - /home/user/work/lefthook-extend-2.yml - lefthook-extends/file.yml - ../extend.yml - projects/*/specific-lefthook-config.yml

源码中extend使用afero.Glob展开通配符,并支持递归合并(被 extend 的文件里还可以继续 extend),同时通过visited集合检测循环引用,若同一路径被重复指定会报错 "possible recursion in extends"(见 internal/config/loader.go)。

remotes

如果你希望在多项目间共享 lefthook 配置,可以使用remotes。lefthook 会自动下载远程仓库中的配置文件并合并到本地lefthook.yml。远程配置中若使用extends,路径必须相对于远程仓库根目录;若远程配置中包含scripts,对应的source_dir也必须位于远程仓库的根目录

# lefthook.yml remotes: - git_url: git@github.com:evilmartians/lefthook ref: v1.0.0 configs: - examples/ruby-linter.yml

合并顺序同样遵循lefthook.yml → remotes → lefthook-local.ymlremotes的加载实现在 loader.go:每个 remote 通过git_url+ref定位远程缓存目录,configs未指定时默认使用lefthook.ymlDefaultConfigName)。

source_dirsource_dir_local

  • source_dir默认.lefthook/:存放脚本文件的目录,其下按 Git hook 名分子目录,每个子目录放对应 hook 的脚本文件:
.lefthook/ ├── pre-commit/ │ ├── lint.sh │ └── test.py └── pre-push/ └── check-files.rb
  • source_dir_local默认.lefthook-local/:存放本地脚本文件(不纳入 VCS)。当你有lefthook-local.yml且需要引用不同的本地脚本时非常有用:
# lefthook-local.yml source_dir_local: .lefthook-local/

两个默认值在源码常量中定义(DefaultSourceDir = ".lefthook"DefaultSourceDirLocal = ".lefthook-local",见 internal/config/loader.go)。

output

output用于精细控制输出内容的详细程度,可选的打印项包括meta, summary, success, failure, execution, execution_out, execution_info, skips,默认全部开启。也可以设置output: false一键关闭所有输出(此时只打印错误):

# lefthook.yml output: - meta # 打印 lefthook 版本 - summary # 打印汇总块(成功与失败的步骤) - empty_summary # 无步骤可运行时打印汇总标题 - success # 打印成功步骤 - failure # 打印失败步骤 - execution # 打印执行日志 - execution_out # 打印执行输出 - execution_info # 打印 `EXECUTE > ...` 日志 - skips # 打印 "skip"(无文件匹配时)

该列表还可以通过环境变量LEFTHOOK_OUTPUT覆盖:

LEFTHOOK_OUTPUT="meta,success,summary" lefthook run pre-commit

rc

rc提供一个rc 文件,本质是一个简单的sh脚本。它的主要用途是设置那些非 shell 程序无法访问的环境变量。典型场景包括:

  • 使用 GUI 程序(如 VSCode)触发 Git hooks;
  • 引用的可执行文件只存在于经过修改的$PATH中(如 rbenv、nvm、fnm 管理下的命令);
  • GUI 程序无法定位lefthook可执行文件;
  • 想在lefthook.yml中使用控制可执行文件行为的环境变量。

例如,你的npm由 nvm 管理,路径在/home/user/.nvm/versions/node/v15.14.0/bin/npm,而 GUI 程序找不到它:

# lefthook-local.yml # 文件名可自选,可在多个项目间共享;确保路径是绝对路径。 rc: ~/.lefthookrc

若路径包含空格,需要加引号:

# lefthook-local.yml rc: '"${XDG_CONFIG_HOME:-$HOME/.config}/lefthookrc"'

在 rc 文件中导出或修改环境变量:

# ~/.lefthookrc # nvm 方式 export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # fnm 方式 export FNM_DIR="$HOME/.fnm" [ -s "$FNM_DIR/fnm.sh" ] && \. "$FNM_DIR/fnm.sh" # 或者直接追加 PATH PATH=$PATH:$HOME/.nvm/versions/node/v15.14.0/bin

修改后必须重新安装 Git hooks 使其生效:

$ lefthook install -f

此后,任何运行 hooks 的程序都会获得调整后的$PATH,从而能够找到npm等工具。

Git hook 配置:commandsscriptsjobs

顶层配置中,每个 Git hook(如pre-commitcommit-msg,也可以是你自定义的 hook,如testcheck-docs)下可以定义命令、脚本与作业。详见 docs/configuration/Hook.md、docs/configuration/Commands.md、docs/configuration/Scripts.md 与 docs/configuration/jobs.md。

Git hook 基本结构

# lefthook.yml # Git hook pre-commit: jobs: - run: yarn lint {staged_files} --fix stage_fixed: true # 自定义 hook check-docs: jobs: - run: yarn check-docs - run: typos

源码中,hook 名称通过正则^(?P<hookName>[^.]+)\.(?:scripts|commands|jobs)识别,支持在本地配置中追加额外的自定义 hook(见 internal/config/loader.go 与 loader.go)。

commands

commands定义 hook 要执行的命令,每条命令有名字和对应的 run 选项:

# lefthook.yml pre-commit: commands: lint: ... # command options

每条命令可用的选项包括:runskiponlytagsglobfilesfile_typesenvrootexcludefail_textstage_fixedinteractiveuse_stdinpriority。这些选项的逐个说明见 docs/configuration/Commands.md 及 docs/configuration/run.md、docs/configuration/glob.md、docs/configuration/files.md 等子文档。

scripts

脚本存放在<source_dir>/<hook-name>/目录下,是项目根目录中运行的自有可执行文件。添加一个pre-commithook 脚本的流程:

  1. 运行lefthook add -d pre-commit
  2. 编辑.lefthook/pre-commit/my-script.sh
  3. lefthook.yml中登记:
# lefthook.yml pre-commit: scripts: "my-script.sh": runner: bash

典型实战:写一个检查 commit 模板的脚本.lefthook/commit-msg/template_checker

INPUT_FILE=$1 START_LINE=`head -n1 $INPUT_FILE` PATTERN="^(TICKET)-[[:digit:]]+: " if ! [[ "$START_LINE" =~ $PATTERN ]]; then echo "Bad commit message, see example: TICKET-123: some text" exit 1 fi

然后在lefthook.yml中让commit-msghook 运行它:

# lefthook.yml commit-msg: scripts: "template_checker": runner: bash

当执行git commit -m "bad commit text"时,template_checker会被执行;由于提交信息不匹配TICKET-123: ...模式,提交过程会被中断。

使用args为脚本追加参数。注意:配置了args后,Git 传入的参数会被省略,如需保留请使用{0}模板:

commit-msg: scripts: "template_checker": runner: bash args: "{0}"

jobs

jobs(自 lefthook1.10.0起)提供更灵活的任务定义方式,同时支持命令和脚本,并支持分组以实现高级流程控制。命名 job 会跨extends和本地配置按名称合并,未命名 job 按定义顺序追加;分组(group)内的 job 可拥有自己的并行(parallel)或管道(piped)流程,分组上的globrootexclude会应用到组内所有嵌套 job(目前仅这三个选项作用于组级别,其余选项需在单个 job 上设置)。

# lefthook.yml pre-commit: parallel: true jobs: - name: migrate root: backend/ glob: "db/migrations/*" group: piped: true jobs: - run: bundle install - run: rails db:migrate - run: yarn lint --fix {staged_files} root: frontend/ stage_fixed: true - run: bundle exec rubocop root: backend/ - run: golangci-lint root: proxy/ - script: verify.sh runner: bash

该配置中,migrate组内的两个 job 以管道方式依次执行(bundle installrails db:migrate),而其余 job 并行运行。

配置加载流程小结

结合源码(internal/config/loader.go 与 internal/config/config.go),lefthook 的配置加载可以归纳为四个步骤:

  1. 定位主配置:按扩展名与基础名称顺序查找第一个存在的文件(也支持LEFTHOOK_CONFIG环境变量直接指定配置文件路径,见 loader.go);
  2. 加载次级配置:依次合并主配置的extendsremotes远程配置,再合并可选的lefthook-local本地配置及其extends(loader.go);
  3. 合并 hook:逐个 hook 执行合并(含{cmd}模板替换、命名 job 按名覆盖、setup前置追加等特殊逻辑,loader.go);
  4. 解析为结构体main.Merge(secondary)后统一反序列化到Config结构体,并处理colors等运行期选项(loader.go)。

理解这套流程后,你就能准确预判"哪个配置会赢",从而在团队共享配置与个人本地配置之间做出清晰的分层设计:把公共的 hook、命令放在lefthook.yml中,把个人的rc、调试开关与专属覆盖放在被 gitignore 的lefthook-local.yml中。更多顶层配置项(如colorsno_ttyskip_lfstemplatesassert_lefthook_installed)的逐项说明,可继续阅读 docs/configuration/README.md 中列出的对应子文档。

【免费下载链接】lefthookFast and powerful Git hooks manager for any type of projects.项目地址: https://gitcode.com/GitHub_Trending/le/lefthook

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询