ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

lefthook run 命令实战指南:手动触发 Git Hook、按 Job/Tag 筛选与文件模板覆盖

lefthook run 命令实战指南:手动触发 Git Hook、按 Job/Tag 筛选与文件模板覆盖 lefthook run 命令实战指南手动触发 Git Hook、按 Job/Tag 筛选与文件模板覆盖【免费下载链接】lefthookFast and powerful Git hooks manager for any type of projects.项目地址: https://gitcode.com/GitHub_Trending/le/lefthooklefthook run是 lefthook 中最核心的执行命令它负责加载 lefthook 配置取出某个 hook 名下配置的全部命令与脚本并执行。安装到.git/hooks/下的 Git hooks 在触发时如git commit、git push也是隐式调用lefthook run hook-name来完成工作的。读完本文你将掌握lefthook run的全部用法——从最基本的手动跑一遍某个 hook到用--job/--tag精准筛选任务、用--all-files/--file覆盖文件模板并理解其底层执行链路配置加载、命令替换、并行/串行调度。lefthook run是什么官方文档的定义非常精炼执行某个给定 hook 名下配置的命令和脚本Executes the commands and scripts configured for a given hook。安装后的 Git hooks 会隐式调用lefthook run因此它既是手动调试的入口也是 Git 触发场景下真正干活的那个进程。典型配置与使用流程假设项目根目录下有一份 lefthook.yml 风格的配置# lefthook.yml pre-commit: jobs: - name: lint run: yarn lint --fix {staged_files} test: jobs: - name: test run: yarn test先安装 hook$ lefthook install然后即可用lefthook run手动触发或直接通过 Git 命令触发$ lefthook run test # 运行 yarn test $ git commit # 触发 pre-commit hook运行 yarn lint --fix $ lefthook run pre-commit # 运行 pre-commit hook同样执行 yarn lint --fix值得注意的是配置中test并非标准的 Git hook 名称但它依然可以被lefthook run test手动触发——这说明lefthook run接受任意 hook 名只要它在配置中被定义即可。而标准的 Git hooks如pre-commit既会被 Git 隐式调用也可以手动运行。从源码看这一判断位于 internal/command/run.go 的resolveHook中若传入的 hook 名不在配置里且该名字属于 lefthook 已知的 Git hooks 列表config.KnownHook则打印 debug 日志并静默跳过否则直接返回错误hook name doesnt exist in the config。为什么需要手动运行手动运行的价值在于快速调试改完lefthook.yml不必真的去git commit直接lefthook run pre-commit即可验证非 Git 场景触发自定义 hook 名如上面的test不会由 Git 自动触发只能靠手动lefthook run test带参数验证可以在命令行追加 Git 参数模拟真实的 commit/push 场景。只运行特定的 Job--job与--tag当某个 hook 名下配置了多个 job 时默认全部执行你可以用--job或--tag精确挑选$ lefthook run pre-commit --job lints --job pretty --tag checks--job name只运行指定名称的 job可重复传入多个--tag tag只运行带有指定 tag 的 job可重复传入多个。两者可以组合使用筛选逻辑是取并集只要 job 命中了任一--job名称或任一--tag就会被执行。源码中的筛选逻辑在 internal/run/controller/job.go 的runJob中可以看到精确的实现if len(scope.opts.RunOnlyJobs) ! 0 !slices.Contains(scope.opts.RunOnlyJobs, job.Name) { return result.Skip(job.PrintableName(id)) } if len(scope.opts.RunOnlyTags) ! 0 (!utils.Intersect(scope.opts.RunOnlyTags, job.Tags) !utils.Intersect(scope.opts.RunOnlyTags, scope.tags)) { return result.Skip(job.PrintableName(id)) }即job 名称必须严格命中--job列表而 tag 命中比较宽松——job 自身的tags或 hook 级继承下来的scope.tags中任何一个与--tag列表相交即可。被筛掉的 job 会以 Skip 结果记录并不会执行。对 group 的传播行为从 internal/run/controller/scope.go 的scope.extend可见一个细节当--job指定的是某个 group 的名字时lefthook 会清空RunOnlyJobs转而运行该 group 下的全部子 job——也就是说用 group 名筛选会展开这个组而不是只挑组内同名子任务。集成测试 tests/integration/cli_run_only.txt 完整验证了--job a --job c --job db --job lint与--tag red的筛选结果包括命令commands:也会被--job命中的行为。指定文件--all-files与--file命令模板中的文件占位符如{staged_files}默认由 lefthook 根据 Git 状态自动填充。你可以用以下两个参数强制覆盖这些模板$ lefthook run pre-commit --all-files $ lefthook run pre-commit --file file1.js --file file2.js--all-files把所有文件模板替换为{all_files}即仓库中的全部文件--file path把文件模板替换为指定的文件列表可重复传入多个。一个容易踩坑的点原文档特别强调如果两者同时指定--all-files会被忽略以--file列表为准。源码中的实现在 internal/command/run.go 的getFiles中可以看到覆盖逻辑if args.FilesFromStdin { // 从 STDIN 读取文件列表 } else if args.AllFiles { files, err : repo.AllFiles() return append(args.Files, files...) } return args.Files--file传入的值直接进入args.Files只有未使用--file且传了--all-files时才调用repo.AllFiles()获取全部文件。两者并存时由于args.Files已非空--all-files分支的追加结果被跳过印证了忽略--all-files的文档描述。文件列表最终会进入命令构建器internal/run/controller/command/build_command.go 的buildReplacer当opts.ForceFiles非空时会用replacer.NewMocked将{staged_files}、{push_files}、{all_files}、{files}全部替换为强制指定的文件列表并经过 shellescape 转义internal/run/controller/command/replacer/replacer.go避免含空格或特殊字符的文件名破坏命令。集成测试 tests/integration/files_override.txt 验证了--all-files输出仓库全部文件包括带逗号的文件名c,file.rb、--file则精确输出给定列表甚至允许传入ghost.file这类不存在的文件。空文件列表的处理若强制指定的文件列表为空或文件模板替换后为空lefthook 默认会跳过该 job除非加上--force。相关逻辑在 internal/run/controller/command/build_command.goreplacer.HasEmpty()为真且未启用--force时返回SkipError{no files for inspection}job 以 Skip 结果呈现不执行命令。完整命令行参数参考lefthook run的完整用法为lefthook run hook-name [args...] [options]其全部 flag 定义于 cmd/run.go汇总如下参数别名说明对应源码字段--verbose-v开启 debug 日志args.Verbose--colors on\|off\|auto颜色输出开关默认autocolors--job name只运行指定名称的 job可重复args.RunOnlyJobs--tag tag只运行带指定 tag 的 job可重复args.RunOnlyTags--command name只运行指定的命令可重复args.RunOnlyCommands--exclude pattern从所有文件模板中排除指定文件args.Exclude--file path用指定文件覆盖文件模板可重复args.Files--force-f即使没有文件变更也不跳过args.Force--all-files将文件模板替换为{all_files}args.AllFiles--no-auto-install不隐式同步/安装 hooksargs.NoAutoInstall--no-stage-fixed忽略配置中的stage_fixed: trueargs.NoStageFixed--no-tty视为没有连接 TTYargs.NoTTY--skip-lfs不运行 LFS hooksargs.SkipLFS--fail-on-changes若有文件被改动则以退出码 1 结束args.FailOnChanges--fail-on-changes-diff因文件改动失败时输出 diffargs.FailOnChangesDiff--files-from-stdin从 STDIN 解析文件列表支持\0分隔args.FilesFromStdin容易被忽略的几个参数--files-from-stdin从标准输入读取文件列表并合并进args.Files。解析逻辑见 internal/command/run.go 的parseFilesFromString它同时兼容换行与\0NUL分隔的输入——后者正是git diff --name-only -z这类命令的输出格式可与管道配合使用。--fail-on-changes/--fail-on-changes-diff用于检查文件是否被改动的守护场景。其取值优先级为命令行参数 hook 配置的fail_on_changes 默认行为且fail_on_changes支持never/always/ci/non-ci等取值逻辑见 internal/command/run.go。同时 hook 名后追加的[args...]会以{0}、{1}……形式注入命令模板模拟真实 Git 传给 hook 的参数。--no-tty/--no-stage-fixed/--skip-lfs分别用于在 CI 等无交互终端场景禁用 spinner、临时关闭某 job 的stage_fixed: true自动暂存、以及跳过 Git LFS hook 的执行。底层执行链路一次lefthook run内部发生了什么从 internal/command/run.go 的Lefthook.Run方法可以看出完整流程环境开关检查若环境变量LEFTHOOK为0或false直接返回不执行用于 CI 中一键禁用所有 hooks预取 Git 状态repo.CacheGitCommands()并行预计算 staged/push 文件等减少后续 IO 等待加载配置LoadConfig()读取 lefthook 配置文件文件不存在时打印警告并正常返回版本校验若配置中声明了min_version会校验当前 lefthook 版本不满足则报错逻辑见 internal/command/run.go隐式同步 hooks除非显式传--no-auto-install或配置关闭了no_auto_install否则会检查并更新已安装的 Git hooks 以匹配最新配置——这正是改完配置自动生效机制的来源解析 hookresolveHook确认 hook 存在并检测parallel与piped不能同时为true的冲突收集文件getFiles处理--files-from-stdin、--all-files、--file的优先级归一化任务config.CommandsToJobs与config.ScriptsToJobs把旧的commands:/scripts:配置统一转换成jobs--command追加进RunOnlyJobs调度执行runHook通过 internal/run/run.go 进入 controller按 hook 的parallel设置走并发concurrently或串行sequentially支持piped断管跳过执行见 internal/run/controller/controller.go结果汇总执行结束后打印 summary若有任一 job 失败则以非零退出码结束internal/command/run.go。值得一提的是controller 在启动时会用utils.NewCachedReader(os.Stdin)缓存标准输入保证多个 job如多个use_stdin: true的脚本都能读到同一次 Git 通过 STDIN 传入的数据。实战建议调试配置时用--job精准定位一个 hook 下有多个 job 时先lefthook run hook --job name单独验证避免其他 job 干扰输出CI 中禁用全部 hooks设置环境变量LEFTHOOK0即可让所有lefthook run调用直接返回无需改配置配合-v观察模板替换lefthook run hook -v会输出每条最终命令的 debug 日志[lefthook] job: ...是排查文件模板、转义问题的利器利用--force跳过空文件跳过逻辑当文件列表为空但确实希望执行命令例如只想验证脚本本身时加-f强制运行让--all-files与--file二选一两者语义互斥混用时结果以--file为准保持命令可读性建议只传一种。如果需要在安装、卸载、校验配置等其他环节做进一步排查可参考 docs/usage/commands/install.md、docs/usage/commands/uninstall.md 与 docs/usage/commands/validate.mdlefthook run本身的全部命令行定义可随时在 cmd/run.go 中查阅。【免费下载链接】lefthookFast and powerful Git hooks manager for any type of projects.项目地址: https://gitcode.com/GitHub_Trending/le/lefthook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表