Worktrunk 钩子(wt hook)完全指南:worktree 生命周期自动化、模板变量与安全审批
【免费下载链接】worktrunkWorktrunk is a CLI for Git worktree management, designed for parallel AI agent workflows项目地址: https://gitcode.com/GitHub_Trending/wo/worktrunk
wt hook是 Worktrunk 的钩子系统:它允许你把任意 shell 命令挂接到 worktree 生命周期的关键节点上,在wt switch、wt merge、wt remove以及 Worktrunk 发起的提交(wt step commit、wt step squash)中自动执行,也可以随时通过wt hook <type>手动触发。本文以官方文档 hook.md 为骨架,结合仓库源码(hooks.rs、hook_plan.rs、hook_commands.rs、expansion.rs 等)深入讲解五种事件的 pre/post 钩子、三种 TOML 配置形态、完整的模板变量体系、安全审批模型,以及过滤器、函数和手动调用方法。读完你将能够为并行 AI Agent 工作流配置出"创建即装依赖、合并即部署、删除即清理"的完整自动化链路。
Hook 类型总览:十个钩子、五种事件
钩子按生命周期事件分为五组,每组都有pre-(阻塞)与post-(后台)两个变体:
| 事件 | pre-(阻塞) | post-(后台) |
|---|---|---|
| switch | pre-switch | post-switch |
| create | pre-start | post-start |
| commit | pre-commit | post-commit |
| merge | pre-merge | post-merge |
| remove | pre-remove | post-remove |
两种变体的执行模型完全不同:
pre-*钩子阻塞命令:在操作的关键节点前同步运行,失败即中止整个操作(fail-fast)。例如pre-merge中的测试失败会让合并终止。post-*钩子在后台运行:输出写入日志文件,可通过wt config state logs查找和管理日志(详见 config.md)。wt hook <type> --foreground可以让某个后置钩子改在前台运行一次,使输出直接到达终端。加-v可以看到后台钩子的模板变量;wt hook <type> --dry-run可以预览将要执行的命令。
最常用的创建钩子是post-start——它在后台运行开发服务器、文件复制、构建等任务,不阻塞 worktree 的创建。除非后续步骤必须等它完成,否则优先用post-start而不是pre-start。
各钩子的用途如下:
| 钩子 | 用途 |
|---|---|
pre-switch | 在切换前的源 worktree 中运行——覆盖创建、切换到已存在 worktree、或停留在当前三种情况 |
post-switch | 在所有切换结果(创建、切换到已存在、停留当前)后触发 |
pre-start | 新 worktree 创建时运行一次,阻塞post-start/--execute直到完成:依赖安装、env 文件生成 |
post-start | 新 worktree 创建时运行一次,后台执行:开发服务器、长构建、文件监听、缓存复制 |
pre-commit | 格式化、lint、类型检查——在任何 Worktrunk 提交(wt step commit、wt step squash以及wt merge产生的提交)之前运行 |
post-commit | CI 触发、通知、后台 lint |
pre-merge | 测试、安全扫描、构建验证——在 rebase 之后、合并到目标分支之前运行 |
post-merge | 部署、通知、安装更新后的二进制。如果目标分支有 worktree 则在其中运行,否则在主 worktree 运行 |
pre-remove | worktree 删除前的清理:保存测试产物、备份状态。在即将被删除的 worktree 中运行 |
post-remove | 停止开发服务器、移除容器、通知外部系统。模板变量指向已删除的 worktree |
merge 的钩子执行顺序
在一次wt merge期间,阻塞钩子按如下顺序运行:
pre-commit → pre-merge → pre-remove合并完成后,所有post-*钩子一起启动,各自锚定在自己的 worktree 上——post-merge、post-switch、post-remove在目标 worktree,post-commit在提交产生所在的 worktree。如果合并恰好删除了该 worktree,post-commit会被报告为 skipped 而不是执行——因为钩子启动时 worktree 已经不存在了。需要在删除前完成的工作请使用pre-remove,或者用--no-remove保留 worktree。完整管线见 merge.md。
这一"锚定 worktree 已被删除则丢弃后台管线"的行为在源码中有明确实现:HookAnnouncer::mark_worktree_removed记录被删除的 worktree,flush时run_hooks_background会先按锚点路径 partition 掉这些管线,并打印Skipped {hook_type}: {summary} — worktree removed警告与use pre-remove提示(见 hooks.rs)。源码注释指出:锚点 worktree 被清空后,若仍把管线 spawn 进去,仓库发现逻辑会向上回溯解析到主 worktree,让任意项目代码跑在用户从未选择的 worktree 中——因此"丢弃并报告"是刻意的安全设计。
安全模型:项目命令的首次审批
项目钩子(来自仓库内的.config/wt.toml)是随仓库分发的任意代码,在首次运行时需要审批。Worktrunk 把审批门禁放在命令执行之前,典型提示如下:
▲ repo needs approval to execute 3 commands: ○ pre-start install: npm ci ○ pre-start build: cargo build --release ○ pre-start env: echo 'PORT={{ branch | hash_port }}' > .env.local ❯ Allow and remember? [y/N]要点:
- 审批结果保存到
~/.config/worktrunk/approvals.toml - 命令一旦变更,需要重新审批
- 拒绝会跳过该次操作的所有项目命令(包括已经批准过的),继续执行其余部分;已保存的审批不受影响
- 使用
--yes跳过提示——适合 CI 与自动化场景 - 使用
--no-hooks完全跳过钩子——该选项被运行钩子的命令接受(wt switch、wt merge、wt remove、wt step commit、wt step squash),但wt hook本身不接受
审批可通过wt config approvals add和wt config approvals clear管理。
源码级的安全保障:冻结的审批计划
从源码结构看,审批与执行之间有一个刻意的"冻结"设计。操作驱动的钩子(pre-merge、post-merge、pre-remove、post-remove、post-switch、pre-start、post-start)在状态变更(如 rebase 可能重写 feature 分支自己的.config/wt.toml)之前做审批,在变更之后执行。若执行时二次读取磁盘配置,变更后的配置可能选出未审批的命令——在全新 clone 上这就是远程代码执行(TOCTOU 竞态)。
ApprovedHookPlan(hook_plan.rs)从结构上堵死这个缺口:审批门禁只做一次命令选择并冻结为计划,执行器只消费这份冻结值,不持有ProjectConfig、不再次调用load_project_config()——重新派生在编译层面就不可能。HookPlan::approve负责交互式/--yes门禁,approve_readonly用于无法弹窗的 picker 与wt step prune(只运行已审批命令,未审批的项目管线被丢弃)。模块内的approved_plan_lookup_is_frozen_and_anchor_scoped等测试锁定了这一不变量。
另一类钩子(pre-commit、post-commit、pre-switch、手动wt hook <type>、别名)属于"调用时解析":门禁与执行之间没有任何东西变更.config/wt.toml,且执行器通过同一个Repository实例读取(项目配置被缓存在OnceCell中,二次读取是缓存命中),因此重读是安全的(hooks.rs 模块文档)。
配置:位置与三种钩子形态
钩子可以定义在项目配置(.config/wt.toml)或用户配置(~/.config/worktrunk/config.toml)中,两者格式完全相同。项目配置从命令所在 worktree读取——即wt运行的那个 worktree(源码注释强调:无论钩子"关于"哪个 worktree,命令都从调用方 worktree 的.config/wt.toml选择,与wt config show读取的是同一个文件)。
钩子根据其 TOML 形状有三种形态。
字符串 = 单条命令:
pre-start = "npm install"表 = 多条命令并发运行:
[post-start] server = "npm run dev" watch = "npm run watch"管线 = 一系列按顺序执行的[[hook]]块。每个块是一个步骤;块内的多个 key 并发运行。某个步骤失败会中止后续步骤:
[[post-start]] install = "npm ci" [[post-start]] build = "npm run build" server = "npm run dev"这里install先运行,然后build与server一起运行。
源码层面,这三种形态由CommandConfig的反序列化器处理(commands.rs):字符串 → 单个HookStep::Single(unnamed);表 → 单 key 折叠为Single(named)、多 key 生成HookStep::Concurrent;数组 → 每个元素一个步骤。内部模型HookStep只有两种:Single(串行)和Concurrent(并行)。值得注意的两个细节:
- 命令名不能包含冒号(
validate_no_colons),否则会破坏日志文件名的解析与user:/project:过滤语法; - 空表(如所有命令都被注释掉的
[post-switch])必须产生零个步骤,否则后台执行路径在空 vec 上索引会 panic——commands.rs 中有针对 issue #2634 的回归测试。
模板预览语义
模板在管线启动前做语法检查,在每个步骤运行时渲染——因此一个步骤可以把 per-branch 变量(wt config state vars,见 config.md)存下来,供后续步骤通过{{ vars.<key> }}读取。由于更早的步骤仍可能修改这些值,预览时用占位引用代替解析:wt hook <type> --dry-run和wt hook show --expanded会把{{ vars.thing | default('none') }}渲染成{{ vars.thing }}——引用是"已定义"的,所以default永远不触发——而其他所有变量正常展开。对输入做变换的过滤器仍会运行(作用于占位文本),其输出与其他值一样做 shell 转义:{{ vars.thing | upper }}预览为'{{ VARS.THING }}'。
大多数钩子不需要[[hook]]块。当存在依赖链时才用——典型场景是先装依赖、再并发跑构建与开发服务器这类"必须先完成前置步骤"的 setup。
项目钩子与用户钩子
| 方面 | 项目钩子 | 用户钩子 |
|---|---|---|
| 位置 | .config/wt.toml | ~/.config/worktrunk/config.toml |
| 作用域 | 单个仓库 | 所有仓库(或按项目限定,见 config.md 中的用户级项目特定设置) |
| 审批 | 需要 | 不需要 |
| 执行顺序 | pre-*:在用户钩子之后。post-*:与用户钩子并行 | pre-*:最先。post-*:与项目钩子并行 |
当用户与项目都定义了同名钩子时,可用user:name或project:name语法指定运行哪一个(过滤解析见 hook_filter.rs,支持user:/project:裸前缀、user:foo/project:foo具名过滤)。
并发语义需要特别注意:pre-*钩子阻塞命令,两个来源合为一条管线——用户命令先跑,其失败会跳过项目钩子。post-*钩子在后台运行,每个来源是各自独立的分离管线——它们同时启动、互不等待,一方失败不影响另一方继续运行。来源内部的顺序仍由你的[[hook]]块决定;post-*跨来源则没有任何顺序。两个post-*钩子如果写同一个文件、或在同一个 worktree 里跑git,会互相竞争——所以互相依赖的命令应放在同一个来源中。源码中into_source_groups把用户步骤与项目步骤分成独立管线(HookAnnouncer::add_groups与HookPlanBuilder::add中稳定排序保证 User 条目始终在 Project 之前),正是"用户钩子失败不得中止项目钩子"这一约束的结构化实现。
模板变量
钩子可以使用在运行时展开的模板变量:
| 类别 | 变量 | 描述 |
|---|---|---|
| active | {{ branch }} | 分支名;分离头(detached)worktree 中未定义 |
{{ worktree_path }} | worktree 路径 | |
{{ worktree_name }} | worktree 目录名 | |
{{ commit }} | 分支 HEAD SHA | |
{{ short_commit }} | 按core.abbrev缩写的分支 HEAD SHA | |
{{ upstream }} | 分支上游(若跟踪远程分支) | |
| operation | {{ base }} | 基础分支名(仅 switch/create) |
{{ base_worktree_path }} | 基础 worktree 路径 | |
{{ target }} | 目标分支名 | |
{{ target_worktree_path }} | 目标 worktree 路径(目标有 worktree 时) | |
{{ pr_number }} | PR/MR 编号(switch 与 create 钩子;通过pr:N/mr:N切换时) | |
{{ pr_url }} | PR/MR 网页地址(switch 与 create 钩子;通过pr:N/mr:N切换时) | |
| repo | {{ repo }} | 仓库目录名 |
{{ repo_path }} | 仓库根目录的绝对路径 | |
{{ owner }} | 主远程的 owner 路径(可能含子组) | |
{{ remote_repo }} | 主远程 URL 中的仓库名(不含.git) | |
{{ primary_worktree_path }} | 主 worktree 路径 | |
{{ default_branch }} | 默认分支名 | |
{{ remote }} | 主远程名 | |
{{ remote_url }} | 远程 URL | |
| exec | {{ cwd }} | 钩子命令运行的目录 |
{{ hook_type }} | 正在运行的钩子类型(如pre-start、pre-merge) | |
{{ hook_name }} | 钩子命令名(如有命名) | |
{{ args }} | 从 CLI 转发的令牌——见下文"手动运行钩子" | |
| user | {{ vars.<key> }} | 来自wt config state vars的 per-branch 变量(见 config.md) |
repo类变量(repo、repo_path、owner、remote_repo、primary_worktree_path、default_branch、remote、remote_url)在整个仓库内恒定——default_branch在每个 worktree 中相同。active类变量(branch、worktree_path、worktree_name、commit、short_commit、upstream)则随 worktree 变化。
裸变量视角:base 与 target
裸变量(branch、worktree_path、commit)指向操作作用的分支:switch/create 时是目标,merge/remove 时是来源。base和target给出另一侧:
| 操作 | 裸变量 | base | target |
|---|---|---|---|
| switch/create | 目标 | 你从哪里来 | = 裸变量 |
| commit(merge/squash 期间) | 被 squash 的 worktree | = 裸变量 | 集成目标 |
| merge | 被合并的 feature | = 裸变量 | 合并目标 |
| remove | 被删除的分支 | = 裸变量 | 你最终所在之处 |
所有钩子共享同一视角——{{ branch | hash_port }}在post-start与post-remove中产生相同的端口。这在源码中由TemplateVars统一组装:for_post_switch根据SwitchResult的 Created/Existing/AlreadyAt 三种结果填充 base/target,with_pr负责把 PR/MR 身份从调用参数(而非操作结果)附加到上下文中(template_vars.rs)。
cwd 的三个例外
cwd是钩子命令运行的 worktree 根目录,通常等于worktree_path,但有三个例外:
pre-switch:钩子在源worktree 运行;worktree_path在目标 worktree 已存在时指向目标——而"创建型切换"尚无目标目录,此时worktree_path停留在源(要在新 worktree 中干活请用pre-start)post-remove:活动 worktree 已消失,钩子在主 worktree 运行post-merge:钩子在目标分支的 worktree 运行(目标无 worktree 时为主 worktree),包括--no-remove场景——此时worktree_path指向的已合并 worktree 仍在磁盘上
未定义变量与条件渲染
未定义变量会报错——可选行为请使用条件或默认值:
[pre-start] # 若跟踪远程分支则 rebase 到上游(例如 wt switch --create feature --base origin/feature) sync = "{% if upstream %}git fetch && git rebase {{ upstream }}{% endif %}"分离头 worktree 不在任何分支上,所以branch在那里未定义——由它派生的base/target名同样未定义,无论手动wt hook还是操作涉及分离头 worktree 都是如此(从一个分离头 worktree 触发的pre-switch的base、落到分离头 worktree 的删除的target),同样的{% if branch %}守卫适用。这与wt list --format=json对该 worktree 报告branch: null一致。
用-v运行任何触发钩子的命令,可以看到本次调用的已解析变量——每个钩子打印一个template variables:块,列出每个在作用域内的变量及其值(条件变量未填充时显示(unset),如wt switch -期间的target_worktree_path)。别名在-v下也如此:wt -v <alias>在管线运行前打印该别名的在作用域变量。手动调用场景下,方向性变量由build_manual_hook_template_vars提供合理的当前 worktree 默认值(当前分支同时作为 base 与 target,见 hook_commands.rs)。
点访问与 default 过滤器
变量支持点访问与default过滤器处理缺失键。JSON 对象/数组值会自动解析,因此当值为{"port": 3000}时{{ vars.config.port }}可用:
[post-start] dev = "ENV={{ vars.env | default('development') }} npm start -- --port {{ vars.config.port | default('3000') }}"Worktrunk 过滤器
模板支持 Jinja2 过滤器来变换值:
| 过滤器 | 示例 | 描述 |
|---|---|---|
sanitize | {{ branch \| sanitize }} | 把/与\替换为- |
sanitize_db | {{ branch \| sanitize_db }} | 数据库安全标识符,带哈希后缀([a-z0-9_],最长 48 字符) |
sanitize_hash | {{ branch \| sanitize_hash }} | 文件系统安全名称,带哈希后缀保证唯一 |
hash | {{ branch \| hash }} | 输入的 3 字符 base36 摘要 |
hash_port | {{ branch \| hash_port }} | 哈希到 10000-19999 端口 |
dirname | {{ repo_path \| dirname }} | 去掉最后一个路径分量(/a/b/c→/a/b) |
basename | {{ repo_path \| basename }} | 只保留最后一个路径分量(/a/b/c→c) |
codename(n) | {{ branch \| codename(2) }} | 确定性的友好单词 |
这些过滤器在 expansion.rs 中注册到模板环境(env.add_filter),并与worktree_path_of_branch函数一同暴露给所有模板。
各过滤器的细节:
sanitize_db产生数据库安全标识符——小写字母数字加下划线、不以数字开头,并附 3 字符哈希后缀避免冲突与保留字。其实现(sanitize_db)按序执行:转小写 → 非字母数字替换为_→ 折叠连续下划线 → 数字开头加_前缀 → 追加基于原始输入的 3 字符哈希 → 总长截断为 48 字符(远低于 PostgreSQL 的 63 字符标识符上限,为拼接路径/标识符留出余量)。sanitize_hash产生文件系统安全名称,并在净化确实改变了输入时追加 3 字符哈希后缀,因此不同的原始值永不碰撞——本就安全的名称原样通过。它调用crate::path::sanitize_for_filename(path.rs)。codename(n)从输入字符串产生确定性友好名称:codename(1)返回一个名词,codename(2)返回形容词-名词,更多数量则追加更多形容词。词库很大(codename(2)约 126 万种组合),因此它通常可单独作为 worktree 叶子名——config.md 的 worktree-path 模板配方展示了它单独使用与放在分支命名父目录下两种用法。实现基于petname::Petnames::medium()(1198 个形容词、1052 个名词),哈希经 SHA-256 并固定宽度取模,保证不同架构、32/64 位构建产生相同结果。hash是裸的 3 字符 base36 摘要(short_hash,46,656 个唯一值),适合在输出预算紧张时自行组合"截断+防碰撞"配方(例如 Unix socket 路径上限 107 字节):
# 截断的分支名 + 哈希:前缀相同也不会碰撞 worktree-path = "/tmp/{{ (branch | sanitize)[:20] }}_{{ branch | sanitize | hash }}"dirname/basename用于遍历路径。它们对位于隐藏目录(如myproject/.git)中的 bare 仓库特别有用,此时{{ repo }}解析为.git:
# 把 worktree 放在 bare 仓库旁边,命名为 <wrapper>.<branch> worktree-path = "{{ repo_path }}/../{{ repo_path | dirname | basename }}.{{ branch | sanitize }}"hash_port用于让每个 worktree 的开发服务器跑在唯一端口上:
[post-start] dev = "npm run dev -- --host {{ branch }}.localhost --port {{ branch | hash_port }}"实现(string_to_port)对输入做哈希后映射到 10000-19999 区间。可以哈希任意字符串,包括拼接结果:
# 每个 repo+branch 组合唯一端口 dev = "npm run dev --port {{ (repo ~ '-' ~ branch) | hash_port }}"变量会自动做 shell 转义——{{ ... }}外面不需要引号,加引号反而可能因特殊字符出问题。
Worktrunk 函数
模板还支持函数做动态查询:
| 函数 | 示例 | 描述 |
|---|---|---|
worktree_path_of_branch(branch) | {{ worktree_path_of_branch("main") }} | 查询某分支 worktree 的路径 |
worktree_path_of_branch给定分支名返回其 worktree 的文件系统路径;该分支没有 worktree 时返回空字符串。它适合引用其他 worktree 中的文件(源码中通过Repository::worktree_for_branch实现,返回的原始路径在输出时统一做 shell 转义):
[pre-start] # 从 main worktree 复制配置 setup = "cp {{ worktree_path_of_branch('main') }}/config.local {{ worktree_path }}"JSON 上下文:模板表达不了的复杂逻辑
钩子会把全部模板变量以 JSON 形式通过 stdin 传入,从而支持模板无法表达的复杂逻辑。模板中未设置的变量在 JSON 中同样缺失,因此读取可选变量时要给默认值——分离头 worktree 中branch就没有默认值:
[pre-start] setup = "python3 scripts/pre-start-setup.py"import json, sys, subprocess ctx = json.load(sys.stdin) if ctx.get('branch', '').startswith('feature/') and 'backend' in ctx['repo']: subprocess.run(['make', 'seed-db'])复制未跟踪文件:wt step copy-ignored
有一个命令值得单独说明:wt step copy-ignored。Git worktree 共享仓库,但不共享未跟踪文件,而这个命令可以把 gitignored 文件在 worktree 之间复制:
[post-start] copy = "wt step copy-ignored"配合[[post-start]]管线,可以"复制完再启动依赖它的后续步骤"(详见 tips-patterns.md 的冷启动消除配方)。
手动运行钩子
wt hook <type>按需运行钩子——适合开发中测试、CI 管线中运行、或失败后重跑。
$ wt hook pre-merge # 运行所有 pre-merge 钩子 $ wt hook pre-merge test # 从两个来源运行名为 "test" 的钩子 $ wt hook pre-merge test build # 运行名为 "test" 和 "build" 的钩子 $ wt hook pre-merge user: # 运行所有用户钩子 $ wt hook pre-merge project: # 运行所有项目钩子 $ wt hook pre-merge user:test # 只运行用户的 "test" 钩子 $ wt hook pre-merge --yes # 跳过审批提示(用于 CI) $ wt hook pre-start --branch=feature/test # 覆盖一个模板变量 $ wt hook pre-merge -- --extra args # 把令牌转发进 {{ args }}user:与project:前缀按来源过滤。单独使用user:或project:运行该来源的全部钩子,或用user:name/project:name运行特定钩子(解析规则见 hook_filter.rs)。若过滤器没有匹配到任何命令,会报错并列出该来源作用域内可用的钩子名(HookCommandNotFound/HookSourceNotConfigured,见 hooks.rs 的no_matching_commands_error)。
运行输出示例:
$ wt hook pre-merge ◎ Running pre-merge project:test cargo test Finished test [unoptimized + debuginfo] target(s) in 0.12s Running unittests src/lib.rs (target/debug/deps/worktrunk-abc123) running 18 tests test auth::tests::test_jwt_decode ... ok test auth::tests::test_jwt_encode ... ok test auth::tests::test_token_refresh ... ok test auth::tests::test_token_validation ... ok test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s ◎ Running pre-merge project:lint cargo clippy Checking worktrunk v0.1.0 Finished dev [unoptimized + debuginfo] target(s) in 1.23s$ wt hook post-start ◎ Running post-start: project @ ~/acme后台钩子的来源独立性在这里同样成立:run_hook的默认路径让每个来源成为独立管线(用户钩子失败不中止项目钩子);而带名字过滤的路径(如wt hook pre-merge test build)会把用户+项目匹配项合并成一条管线——因为你按名字跨来源挑选了具体命令(hook_commands.rs)。若某钩子类型没有配置任何命令,wt hook <type>会打印No <type> hooks configured警告并以成功退出——脚本可以无条件调用wt hook <type>而无需特判空配置。
传值:--KEY=VALUE 的智能路由
--KEY=VALUE会把KEY绑定到该钩子任何命令中出现的{{ KEY }}——与wt <alias>使用的智能路由规则相同。内置变量也可以覆盖:--branch=foo设置钩子模板内的{{ branch }}(worktree 实际分支不会移动)。键中的连字符变成下划线:--my-var=x设置{{ my_var }}(源码中parse_shorthand_token做了这个规范化)。
任何--KEY=VALUE,若其键没有被钩子模板引用,就会作为字面--KEY=VALUE令牌转发进{{ args }}。--之后的令牌也原样转发进{{ args }}。{{ args }}渲染为空格连接、逐元素 shell 转义的字符串;可用{{ args[0] }}索引、{% for a in args %}…{% endfor %}循环、{{ args | length }}计数。源码中args以 JSON 编码的序列注入模板上下文,expand_template把它还原为ShellArgs,从而支持上述全部操作(hook_commands.rs)。
长形式--var KEY=VALUE已弃用但仍有支持:它无条件强制绑定,无论是否有钩子模板引用KEY——当模板只在条件分支里引用键时(如{% if override %}…{% endif %})有用。使用时会打印弃用警告。
实战配方
以下配方可在 tips-patterns.md 中找到完整展开:
- 消除冷启动:
post-start中执行wt step copy-ignored共享构建缓存与依赖;当后续钩子依赖复制结果时,用[[post-start]]管线 - 每 worktree 一个开发服务器:
post-start中执行wt step tether启动开发服务器,并在 worktree 被删除时杀掉其整个进程组,可选子域路由 - 每 worktree 一个数据库:
post-start管线把容器名、端口、连接串存为 per-branch 变量(wt config state vars,见 config.md),后续钩子引用 - 渐进式校验:快速 lint/typecheck 放
pre-commit,昂贵测试与构建放pre-merge - 目标特定钩子:
post-merge中基于{{ target }}分支,实现按环境的部署
命令参考
wt hook - Run configured hooks Usage: wt hook [OPTIONS] <COMMAND> Commands: show Show configured hooks pre-switch Run pre-switch hooks post-switch Run post-switch hooks pre-start Run pre-start hooks post-start Run post-start hooks pre-commit Run pre-commit hooks post-commit Run post-commit hooks pre-merge Run pre-merge hooks post-merge Run post-merge hooks pre-remove Run pre-remove hooks post-remove Run post-remove hooks Options: -h, --help Print help (see a summary with '-h') Global Options: -C <path> Working directory for this command --config <path> User config file path --config-set <toml> Override config with inline TOML, e.g. --config-set list.full=true (repeatable) -v, --verbose... Verbose output (-v: info logs + hook/alias template variables on stderr; -vv: also debug logs and raw subprocess output written to .git/wt/logs/). Set WORKTRUNK_VERBOSE=0|1|2 to apply the same level everywhere — including shell completion, which no flag can reach -y, --yes Skip approval promptswt hook show可以在分页器中列出已配置钩子(用户与项目分区展示,标注(requires approval)),支持--expanded渲染实际命令预览,以及--format=json输出结构化记录(每条含 type、source、name、template、needs_approval、可选的 expanded 字段,见 hook_commands.rs)。
延伸阅读
- 配置总览与
wt config state logs、wt config state vars:config.md - 合并管线的完整钩子顺序:merge.md
- 切换与创建流程中的钩子:switch.md
- 删除流程中的钩子:remove.md
wt step copy-ignored与 step 系列命令:step.md- 钩子实战配方:tips-patterns.md
- 钩子配置解析(三种 TOML 形态):src/config/commands.rs
- 钩子执行与审批门禁:src/commands/hooks.rs、src/commands/hook_plan.rs
- 模板过滤器与函数实现:src/config/expansion.rs
【免费下载链接】worktrunkWorktrunk is a CLI for Git worktree management, designed for parallel AI agent workflows项目地址: https://gitcode.com/GitHub_Trending/wo/worktrunk
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考