Worktrunk FAQ 深度解读:worktree 生命周期、文件足迹与命令审计机制全解析
【免费下载链接】worktrunkWorktrunk is a CLI for Git worktree management, designed for parallel AI agent workflows项目地址: https://gitcode.com/GitHub_Trending/wo/worktrunk
Worktrunk 是一款面向 Git worktree 管理的 CLI,专为并行 AI Agent 工作流设计。本文以官方 FAQ 文档 为主线,系统回答「Worktrunk 与既有 Git 工具的关系、它创建/删除哪些文件、它执行哪些命令、它如何在 Windows 上工作」等高频问题,并深入 src/logging.rs、src/command_log.rs、src/commands/remove.rs 等源码,解释其背后的实现机制。读完本文,你将能准确评估 Worktrunk 的适用场景、掌握-v/-vv排障工具链,并理解它的安全删除与命令审批边界。
Worktrunk 与既有 Git 工作流的对比
FAQ 从四个角度回答了「Worktrunk 相比替代方案有何不同」,核心差异始终是:为每个并行工作单元提供独立目录,并自动化整个生命周期。
vs. 分支切换(branch switching)
分支切换只使用一个目录:一个 Agent 的未提交更改会与下一个 Agent 的工作混杂在一起,或直接阻塞切换。Worktree 则给每个 Agent 一个独立目录,各自拥有独立的文件和索引(index),互不干扰。这正是并行 AI Agent 工作流选择 worktree 模型而非分支切换的根本原因。
vs. 原生git worktree
Git 内置的 worktree 命令可用,但需要手动管理生命周期:
# Plain git worktree workflow $ git worktree add -b feature-auth ../myproject.feature-auth main $ cd ../myproject.feature-auth # ...work, commit, push... $ cd ../myproject $ git merge feature-auth $ git worktree remove ../myproject.feature-auth $ git branch -d feature-authWorktrunk 将上述全流程自动化:
$ wt switch --create feature-auth # Creates worktree, runs setup hooks # ...work... $ wt merge # Merges into default branch, cleans up无需切回主目录 ——wt merge直接在功能 worktree 内运行并把更改合入目标分支,行为类似 GitHub 的 merge 按钮。git worktree本身不提供的能力包括:
- 一致的目录命名与清理校验;
- 项目级自动化(安装依赖、启动服务等 hooks);
- 跨所有 worktree 的统一状态视图(提交、CI、冲突、变更聚合,即
wt list的能力)。
vs. git-machete / git-town
三者作用域不同:
- git-machete:单目录内的分支栈(branch stack)管理;
- git-town:单目录内的 Git 工作流自动化;
- worktrunk:多 worktree 管理,附带 hooks 与状态聚合。
这些工具可以共存 —— 你可以在每个独立 worktree 内部再运行 git-machete 或 git-town。
vs. Git TUI(lazygit、gh-dash 等)
Git TUI 作用于单个仓库。Worktrunk 管理多个 worktree、运行自动化 hooks,并跨分支聚合状态。TUI 可以在每个 worktree 目录内正常工作,二者是不同层级的工具。
Worktree 的磁盘占用与写时复制优化
Worktrees 共享同一个.git目录。每个 worktree 各自新增一份已跟踪文件的检出副本,再加上你复制进去的、被 gitignore 的构建产物。
在 APFS、btrfs 和 XFS 上(不包括ext4 或 NTFS),wt step copy-ignored使用 reflink(写时复制)复制这些产物,使新 worktree 与主 worktree 共享磁盘块。后续构建只重写发生变化的部分,其余部分保持共享。实测数据(来自 FAQ):一台机器上,一个 Rust 仓库的 56 个 worktree,含 40GB 的target/目录,du统计为 2.6TB,实际磁盘占用仅 0.7TB。
从源码看,该命令的实现位于 src/commands/step/copy_ignored.rs:它会将源 worktree 中 gitignored 的文件复制到目标 worktree,若存在.worktreeinclude文件则只复制同时匹配该文件与 gitignore 模式的文件,否则复制全部 gitignored 文件;复制过程通过copy_dir_recursive在可用时使用 COW(reflink)高效处理target/这类大目录,进度输出中会以reflinked/written拆分统计(见 src/commands/step/copy_ignored.rs)。
Worktrunk 是否原生支持堆叠分支(stacked branches)?
不原生支持 —— 堆叠分支工作流是一个庞大的设计空间,Worktrunk 将其视为扩展而非内建特性。社区工具worktrunk-sync会从 git 历史中自动检测分支依赖树,并按照拓扑顺序将每个分支 rebase 到其父分支之上。安装方式为cargo install worktrunk-sync,然后通过自定义子命令机制(见 docs/public/extending.md)以wt sync的方式运行。
如何把未提交更改移动到新的 worktree?
先把更改 stash,创建 worktree,再 pop:
git stash push -u # -u also stashes untracked files wt switch --create feature # new branch off the default branch git stash pop # changes reappear in the new worktreestash 存放在共享的.git目录中,因此从新 worktree 也能访问到。原分支保持干净状态。
需要注意:wt switch --create默认以默认分支(default branch)为基创建新分支。若希望以当前提交为基,需传入--base=@(当当前分支已有超出默认分支的提交时,这是必需的)。
Shell 集成出问题怎么办
如果 shell 集成不生效(没有自动cd、补全缺失、wt不是函数等),可先对照 docs/public/shell-integration.md 的调试清单逐项排查 —— 它覆盖了wt switch打印的每一条警告,以及每个 shell 需要检查的内容。
也可以把问题交给 Agent:在 Claude Code 中安装 Worktrunk 插件,让它运行wt config show、检查 shell 配置文件并定位问题。
如果仍未解决,请附上wt config show的输出、shell 类型(bash/zsh/fish)和操作系统信息提交 issue。FAQ 特别说明:即使问题已经修复,也欢迎提交 issue —— 非标准的成功案例对确保他人能轻松完成 Worktrunk 配置很有价值。
-v/-vv详细级别解析
Worktrunk 有三个详细级别,每一级都是上一级的超集:
| 级别 | Stderr | 文件(.git/wt/logs/) | 适用场景 |
|---|---|---|---|
| (无) | 仅警告 | — | 常规使用 |
-v | + Info:hook 输出、别名模板变量解析 | — | 调试 hooks/别名 |
-vv | 与-v相同 | +trace.log、trace.jsonl、subprocess.log、diagnostic.md | 提交 bug |
实现机制:四层 subscriber 与目标过滤
-vv时,debug 级记录(命令行、进程内 span、有界的子进程预览)路由到trace.log而不是 stderr —— 终端保持可读,深层 trace 落盘。stderr 会打印一行指针,指明文件去向(见 src/logging.rs 的announce_trace_destination,输出形如Verbose logging @ .git/wt/logs/)。
源码层面,src/logging.rs 通过四个分层 subscriber 协作实现路由,每一层由独立的Filter结构性过滤:
| layer | filter | 格式 |
|---|---|---|
| stderr | $RUST_LOG或 flag 基线(Off/Info/Info) | 人类可读、ANSI 样式 |
trace.log | 仅-vv,排除子进程完整输出目标 | 人类可读、纯文本 |
trace.jsonl | 仅-vv,排除两个子进程输出目标 | 每事件一个 JSON 对象(机器可读) |
subprocess.log | 仅-vv,只含子进程完整输出目标 | 原始正文 +$ cmd … seq=N头 |
注意-vv时 stderr 层保持 Info 基线 ——-vv是-v的严格超集,嘈杂的 Debug 级记录只路由到文件层(src/logging.rs)。stderr 与trace.log使用同一套人类可读渲染(✓ git status [wt] 12.3ms),trace.jsonl则是唯一的机器通道,携带src/trace/parse.rs与wt-perf消费的完整结构化字段。
四个文件的受众差异
trace.log:人类可读的 trace(有界、便于 gist 分享);trace.jsonl:同一批记录的机器版本,每行一个 JSON 对象;subprocess.log:原始的、未截断的子进程输出(可能达数 MB);diagnostic.md:面向 bug 报告的诊断包(以性能 profile 开头)。
每个文件都在wt config state logs中有说明,其分类可在 src/commands/config/state.rs 的DIAGNOSTIC_FILES常量中看到。
环境变量与 RUST_LOG 的叠加规则
RUST_LOG一旦设置就覆盖 flag 基线(RUST_LOG=debug wt -v会把-v提升为 debug-on-stderr);- flag 只作用于你输入的那条命令—— shell 补全以独立进程运行,无法传 flag。此时应使用
WORKTRUNK_VERBOSE=0|1|2将级别应用到每一次调用(包括补全)。它是-v/-vv的环境变量等价物,级别 2 会写出同样的trace.log/trace.jsonl/subprocess.log/diagnostic.md四个文件; - 命令上的显式
-v/-vv可以在基线之上进一步提升级别,但永远不会降低这个基线。
从源码看,WORKTRUNK_VERBOSE常量定义于 src/logging.rs(VERBOSE_ENV),其解析是无损的(任何非法值静默归零),因为补全场景下一个坏值会破坏候选列表。合入规则是max:环境变量设定基线,flag 只能提高不能降低。要分析一次缓慢的 tab 补全,请像你的 shell 那样运行它,例如:
WORKTRUNK_VERBOSE=2 COMPLETE=fish wt -- wt switch ''然后用wt config state logs profile渲染结果。
Worktrunk 会创建哪些文件?
FAQ 将 Worktrunk 的文件足迹划分为六类,以下逐一说明。
1. Worktree 目录
由wt switch <branch>在切换到尚无 worktree 的分支时创建;用wt switch --create <branch>创建新分支。默认位置是../<repo>.<branch>(主 worktree 的兄弟目录),可通过用户配置中的worktree-path修改。
从源码看,默认模板为../{{ repo }}.{{ branch | sanitize }}(src/config/user/mod.rs),支持按项目覆盖:worktree_path_for_project()优先取项目级配置,回退到全局worktree-path(src/config/user/accessors.rs)。移除方式:wt remove <branch>同时删除 worktree 目录与分支。
2. 配置文件
| 文件 | 创建者 | 用途 |
|---|---|---|
~/.config/worktrunk/config.toml | wt config create | 用户偏好 |
~/.config/worktrunk/approvals.toml | 审批项目命令时 | 已批准的 hook 与别名命令 |
.config/wt.toml | wt config create --project | 项目 hooks(随仓库提交) |
用户配置位置:Linux/macOS 为$XDG_CONFIG_HOME/worktrunk/(或~/.config/worktrunk/),Windows 为%APPDATA%\worktrunk\。移除方式为直接删除:用户配置rm ~/.config/worktrunk/config.toml,项目配置rm .config/wt.toml(并提交)。
3. Shell 集成
wt config shell install会向 bash、zsh、PowerShell 的 rc 文件追加一行,并为 fish 和 Nushell 整体写入 Worktrunk 自己的 wrapper 与补全文件。每个 shell 得到的文件名见 docs/public/shell-integration.md 的「Files created」一节。移除方式:wt config shell uninstall。
4..git/中的元数据(自动)
Worktrunk 将仓库状态、缓存与日志存放在.git/下:
| 位置 | 用途 | 创建者 |
|---|---|---|
git config worktrunk.* | 缓存的默认分支、切换历史、分支标记、自定义变量 | 各命令 |
.git/wt/cache/{kind}/*.json | 缓存的 CI 状态、观测到的最大 PR/MR 编号(用于确定wt listCI 列宽度)、git 命令结果(merge-tree、集成探测、diff 统计、ancestry 检查、ahead/behind 计数、merge base) | wt list、wt merge、wt remove |
.git/wt/cache/summary/{branch}/{hash}.json | 缓存的 LLM 分支摘要,按 diff hash 内容寻址 | wt list --full、wt switch(当[list] summary = true) |
.git/wt/cache/picker-preview/*.json | 交互式 picker 渲染的预览面板 | wt switch |
.git/wt/logs/{branch}/**/*.log | 后台 hook 输出(按分支嵌套) | hooks、后台wt remove |
.git/wt/logs/commands.jsonl | 命令审计日志(约 2MB 上限) | hooks、LLM 命令 |
.git/wt/logs/trace.log | 供问题报告的人类可读 debug trace | 以-vv运行 |
.git/wt/logs/trace.jsonl | 机器可读 trace(每记录一个 JSON 对象) | 以-vv运行 |
.git/wt/logs/subprocess.log | 原始的未截断子进程 stdout/stderr(可能达数 MB) | 以-vv运行 |
.git/wt/logs/diagnostic.md | 供问题报告的诊断包(以性能 profile 开头) | 以-vv运行 |
.git/wt/trash/<name>-<timestamp> | 暂存的待后台删除 worktree 内容 | wt remove |
以上内容均不被 git 跟踪、不会推送到远端。移除方式:wt config state clear删除所有仓库数据(配置键、缓存、标记、提示、变量、日志与过期 trash),在删除任何无法重新计算的内容前会要求确认,除非传入--yes。
5. Agent 集成
由wt config plugins <agent>安装命令创建,每个都写入 Worktrunk 自身配置目录之外、属于各 Agent 的位置:
| 文件 | 创建者 | 用途 |
|---|---|---|
~/.config/opencode/plugins/worktrunk.ts | wt config plugins opencode install | wt list中的活动标记 |
~/.omp/agent/hooks/pre/worktrunk.ts | wt config plugins pi install | wt list中的活动标记 |
~/.claude/settings.json | wt config plugins claude install-statusline | 添加statusLine条目,运行wt list statusline --format=claude-code |
路径解析规则:OpenCode 遵循$OPENCODE_CONFIG_DIR>$XDG_CONFIG_HOME/opencode>~/.config/opencode;Pi 遵循$PI_CONFIG_DIR、$OMP_PROFILE/$PI_PROFILE与$PI_CODING_AGENT_DIR;Claude Code 遵循$CLAUDE_CONFIG_DIR。两个 plugin 文件是 Worktrunk 自己的,安装时整文件写入;settings.json属于 Claude Code,安装时只合并statusLine键,其余内容保持不变。
wt config plugins claude install与wt config plugins codex install本身不写任何文件 —— 它们运行claude/codex来注册 marketplace 并安装插件,各 CLI 会记录到自己的配置(~/.claude/plugins/、~/.codex/config.toml)。移除方式:wt config plugins opencode uninstall与wt config plugins pi uninstall删除对应 plugin 文件;wt config plugins claude uninstall/codex uninstall通过该 CLI 移除插件与 marketplace;statusline 条目通过编辑settings.json移除。
6. 临时文件(自动)
Worktrunk 会创建名为$TMPDIR/worktrunk-temp-index-*的临时 Git 索引副本。wt list、wt list statusline、wt step diff、wt step commit --dry-run和wt switch用它来检查暂存区或工作树状态,而不改变真实索引。wt list还会创建$TMPDIR/worktrunk-list-objects-*目录,使其 merge 探测不会向仓库添加不可达对象。当系统临时目录不可用时,两者回退到 Git 元数据:worktrunk-list-objects-*位于 Git common 目录下,worktrunk-temp-index-*位于 worktree 的 Git 目录下。正常退出会删除这些文件/目录;进程被中断时可能残留一个,需手动清理。
Worktrunk 不创建什么
- 不在这六类之外创建任何文件:
.git/、Worktrunk 配置目录、worktree 目录、第 3 节的 shell 启动文件与 wrapper 路径、第 5 节的 Agent 配置路径(仅在运行wt config plugins安装时)、系统临时目录; - 不创建全局 git hooks;
- 不修改
~/.gitconfig; - 不启动任何常驻后台进程或守护进程。
Worktrunk 能删除什么?
Worktrunk 可以删除worktree与分支,两者都有安全防护。
Worktree 移除
wt remove镜像git worktree remove:拒绝删除含未提交更改(已暂存、已修改或未跟踪文件)的 worktree。--force标志可以强制删除并丢弃所有这些更改。
即使--force,当注册路径上的目录不再持有该路径注册的 worktree 时(例如 worktree 删除后有人在此克隆,或同仓库的另一个 worktree 移动到了该路径),移除同样会被拒绝。--force只豁免未提交更改,不豁免「目录里到底有什么」的检查 ——git worktree remove对同样的情形也拒绝删除。
要彻底保护某个 worktree(比如它持有本地数据库),请锁定它:
git worktree lock ../myproject.feature-auth --reason "Contains local database"被锁定的 worktree 在wt list中显示⊞。无论是git worktree remove还是 Worktrunk 的任何移除路径 ——wt remove或wt merge—— 都不会删除它们,即使带--force。解锁用git worktree unlock。
从源码看,wt remove的完整流程(src/commands/remove.rs)为:先对所有目标 worktree 做前置校验(干净检查、分支删除安全检查、force 处理),再审批pre-remove/post-remove/post-switchhooks,随后每个目标执行:停止 fsmonitor → 重命名进.git/wt/trash/<name>-<timestamp>/→ 修剪元数据 → 删除分支 → 同步删除暂存目录(前台模式)或生成分离的rm -rf后台进程(默认模式);跨文件系统或被锁定的 worktree 回退到分离进程内的git worktree remove。
分支删除
默认情况下,wt remove只删除内容已并入默认分支的分支。wt list中显示_(同提交、干净)或⊂(已集成)的分支可以安全删除。完整算法见 docs/public/remove.md 的「Branch cleanup」一节 —— 它处理了 squash-merge 与 rebase 工作流中提交历史不同但文件变更一致的情况。
用-D强制删除含未合并更改的分支;用--no-delete-branch无论状态如何都保留分支。在第二个 worktree 中被检出的分支无论如何都会保留(-D也不例外)—— 删除它会使该 worktree 无法解析HEAD,只有git worktree add --force才会产生这种状态。
其他清理机制
wt merge/wt step push—— 目标分支检出的 worktree 会更新到合并后的提交,因此被这些提交删除的文件会从其中消失,被跟踪路径上的忽略文件会被覆盖 —— 与在该 worktree 中运行git merge的结果一致。合并未触及的路径上的未提交更改保持原样(无论是否暂存);合并触及路径上的未提交更改会在合并前被拒绝并指名该文件。wt remove—— 除了移除 worktree 本身,还有两个清理机制:被移除 worktree 自己的git fsmonitor--daemon(core.fsmonitor=true时 git 的每 worktree 文件系统监视器,worktree 消失后会泄漏)会被发送git fsmonitor--daemon stop,若未退出则通过其 IPC socket 解析出的 PID 强制终止(SIGTERM,随后SIGKILL);后台 sweep 会删除.git/wt/trash/中超过 24 小时的条目(前一次后台删除被中断时遗留的目录),并终止 worktree 已不存在的 fsmonitor 守护进程(来自git worktree remove、rm -rf或崩溃的wt造成的孤儿)。这段逻辑对应源码中的run_internal_sweep(src/commands/process.rs),在主要输出之后以 fire-and-forget 方式运行,绝不拖延用户可见的进度。wt config state clear—— 从.git/移除所有 worktrunk 数据(配置键、缓存、标记、提示、变量、日志、过期 trash)。wt config shell install—— 迁移集成到新位置时,会删除留在旧位置的文件:fish 的conf.d/wt.fish(现在是functions/wt.fish)以及残留在<config-dir>/vendor/autoload(现在是<data-dir>/vendor/autoload)下的 nushell wrapper。旧路径是 Worktrunk 自己 wrapper 的所在位置,且以被安装命令命名,因此会被整体取回而不读取内容 —— 留在原位的conf.d/wt.fish会在启动时被 source 并遮蔽新 wrapper。只触碰该确切文件名,每次删除都会打印。wt config shell uninstall—— 从 bash/zsh/PowerShell 的 rc 文件移除集成行,并删除 Worktrunk 的 wrapper 与补全文件(fish 的functions/、conf.d/、completions/;nushell 的vendor/autoload)。卸载不接受命令名,因此会列出这些目录并按 Worktrunk 自己的内容标记识别文件,无论它们以什么二进制名安装;没有标记的文件保持不动。rc 文件属于用户,因此只有运行 init 命令的行才算数 —— 仅提及它、位于注释中、echo内或别名体内的行会保留。uninstall 取走的每一行都会在删除前和删除后各打印一次。wt config plugins opencode uninstall/wt config plugins pi uninstall—— 删除该 Agent 的worktrunk.ts插件文件。只触碰 Worktrunk 自己的文件,Agent 插件目录的其余内容保持不动。
Worktrunk 会执行哪些命令?
Worktrunk 内部运行git命令,并可选地运行gh(GitHub)或glab(GitLab)获取 CI 状态。除此之外,用户定义命令在四种上下文中执行:
- 用户 hooks(
~/.config/worktrunk/config.toml)—— 针对所有仓库的个人自动化; - 项目 hooks(
.config/wt.toml)—— 仓库专属自动化; - LLM 命令(
~/.config/worktrunk/config.toml)—— 提交消息生成与分支摘要; --execute标志—— 显式提供的命令。
审批模型
用户 hooks 与用户别名不需要审批(它们由你定义)。来自项目 hooks 与项目别名的命令在首次运行时需要审批,已批准的命令保存到 approvals 文件(approvals.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]使用--yes可以绕过提示(适用于 CI/自动化场景)。
命令审计日志
所有 hook 执行与 LLM 命令都会记录到.git/wt/logs/commands.jsonl,每行一个 JSON 对象。字段:ts(时间戳)、wt(触发它的 wt 命令)、label(执行内容,如pre-merge user:lint)、cmd(shell 命令)、exit(退出码,后台为null)、dur_ms(耗时,后台为null)。文件在 1MB 时轮转为commands.jsonl.old,存储上限约 2MB。
从源码看,这些字段的写入逻辑位于 src/command_log.rs:MAX_LOG_SIZE = 1_048_576(1MB),写入前检查文件大小、超过即重命名轮转;命令字符串会被截断到 2000 字符(MAX_CMD_LENGTH);每次使用单次write_all保证每行 JSON 原子写入;文件在首次写入时惰性创建(src/command_log.rs 有对应测试)。
查看日志可用wt config state logs get,或直接查询:
# Recent commands $ tail -5 .git/wt/logs/commands.jsonl | jq . # Failed commands $ jq 'select(.exit != 0 and .exit != null)' .git/wt/logs/commands.jsonl清空用wt config state logs clear(实现见 src/commands/config/state.rs,同时覆盖审计日志与诊断日志)。
Worktrunk 在 Windows 上能工作吗?
可以。核心命令、shell 集成与 tab 补全在 Git Bash 和 PowerShell 中都能工作。安装细节见 docs/public/config.md,包括如何避开 Windows Terminal 的wt冲突。
必须安装 Git for Windows—— hooks 使用 bash 语法并通过 Git Bash 执行,因此即使交互 shell 是 PowerShell,也必须有 Git for Windows。
wt switch的交互式 picker 在 Windows 上同样可用,基于 skim 的 crossterm 后端运行。
Worktrunk 如何确定默认分支?
Worktrunk 先查本地 git 缓存,必要时查询远端,没有远端时回退到本地推断。
如果远端的默认分支发生了变更(例如从 master 重命名为 main),用wt config state default-branch clear清除缓存。检测机制的完整说明见wt config state default-branch --help;状态管理子命令的实现位于 src/commands/config/state.rs,支持get/set/clear操作(wt config state default-branch set BRANCH可手动指定)。
为什么for-each或--execute别名在每个 worktree 打印相同的值?
因为别名主体在分发时只渲染一次,在嵌套的wt命令开始迭代之前,变量就被烘焙成了发起调用那个 worktree 的值。如何确认这一点、以及如何把变量推迟到嵌套wt命令中展开,见 docs/public/extending.md 的「Deferring expansion to a nested wt command」一节。
系统依赖要求
Worktrunk 要求Git 2.43 或更新版本。
通过 Cargo 以默认特性安装时,还需要一个 C99 编译器用于 bash 语法高亮。如果 tree-sitter 或 C 编译失败(C99 模式、le16toh未定义),可安装不带语法高亮的版本:
cargo install worktrunk --no-default-features --features cli这会禁用命令输出中的 bash 语法高亮,但保留全部核心功能。语法高亮特性需要 C99 编译器支持,在较老的系统或最小化 Docker 镜像上可能失败。
如何参与贡献
见仓库根目录 README.md 的 Contributing 一节 —— 包括反馈、分享链接以及如何运行测试套件(集成测试位于 tests/integration_tests/)。
【免费下载链接】worktrunkWorktrunk is a CLI for Git worktree management, designed for parallel AI agent workflows项目地址: https://gitcode.com/GitHub_Trending/wo/worktrunk
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考