几周前,我写了一篇关于 git worktrees 的文章 —— 讲解了它们是什么,怎么创建,以及为什么它们比多次克隆代码库更好。这些只是基础。
但仅仅掌握这些基础只是成功的一半。而 Claude Code 不仅仅是在 worktree 的基础上运行,它还原生支持 worktree,拥有专门的参数、自动隔离功能,与 tmux 的深度集成。了解 worktree 存在和理解 Claude Code 如何利用它们的巨大差异,就像拥有一辆车并知道它有运动模式一样。
Claude Code 的创始人 Boris Cherny 发布了五个关于充分利用 worktree 的技巧。我把这些技巧全都测试了一遍。有些真的是大大优化了我的工作流,省去了我从今年一月起一直在用的小修小补(ñapa)。下面一起来看看吧。
技巧 1:--worktree —— 一个参数搞定一个 worktree
在经典的 worktree 工作流程中,你需要进行以下这些操作:
| |
总共三步。虽然不算太复杂,但得想目录名、记住语法,然后还得导航到新目录。如果你一天做五次这个操作,时间一长确实会觉得心累。
Claude Code 将整个过程简化成了一步:
| |
就是这样。Claude 会创建一个临时 worktree,将目录命名为随机生成的名字,自动切换到该目录,并启动会话。当你结束作业后,worktree 会自动清理干净。
我什么时候会用这个功能?每次我想测试一些东西又不想污染当前分支的时候。比如尝试一个激烈的重构,探索另一种设计方案,做某个 spike 实验。如果成功的话,我会合并。如果不成功,worktree 就会消失得无影无踪。
这个功能就像是在你的文本编辑器里打开一个新草稿一样。没有任何负担,甚至无需仪式感。
技巧 2:隔离子代理的 worktrees
如果你已经在 Claude Code 中使用了子代理功能(通过在自定义 agent 中使用 Task,或在主要代理内进行委托操作),你可能会知道这些子代理共享同一个工作目录。这意味着两个子代理可能会覆盖彼此的文件,争抢 git 的 index,或者让 staging area 一团混乱。
解决方案就是:让每个子代理运行在自己的 worktree 中。
当一个代理以 worktree 隔离方式启动子代理时,Claude Code 会进行以下操作:
- 为子代理创建一个临时 worktree。
- 子代理在自己的分支中工作。
- 完成后,变更可以被合并到父 worktree。
- 最后,临时 worktree 会被清理。
简单来说就是:每个子代理都有自己独立的工作台。即使它们同时工作,也不会互相妨碍。
这个改进不仅仅是为了避免冲突。更重要的是,你可以实现真正的 并行化:让一个子代理写测试,另一个实现功能;一个翻译文档,另一个重构认证模块。无需等待,无需阻塞。
技巧 3:isolation: worktree 配置自定义 agents
这才是真正让事情变得有趣的地方。在 Claude Code 中,自定义 agents 是通过 .claude/agents/ 中的 Markdown 文件定义的。而在该文件的 frontmatter 中,你可以包含以下字段:
| |
isolation: worktree 告诉 Claude Code:“每次运行这个 agent,自动给它分配一个独立的 worktree”。无需手动传递 --worktree,也无需手动创建任何内容。隔离完全成为 agent 本身的一个特性。
这有什么用呢?适合那些从设计上就需要隔离的 agents。例如:
激进重构的 agent。 你想要 agent 修改文件、重命名函数、改变目录结构。如果直接在你的工作分支上操作,任何错误都可能是灾难性的。有了 isolation: worktree,这个 agent 会在自己的副本中完成这些更改。你可以查看 diff。如果满意就合并;不满意就 git worktree remove,仿佛什么都没发生。
翻译的 agent。 我就是用它为我的博客做翻译的。这个 agent 会将文章翻译成四种语言,生成 frontmatter,并提交。它需要同时修改很多文件。如果它在我的开发目录工作,会拖慢我的进度。有了自己的 worktree,它可以完成翻译,而我可以继续写下一篇文章。
数据库迁移的 agent。 它可以生成 SQL 文件,对当前的 schema 进行验证并运行测试。全部都在隔离的 worktree 中完成,即使遇到问题也不会带来影响。
isolation: worktree 的关键在于将隔离转变为 agent 的属性,而不是让每次你运行时做出决定。好比一个汽车有了气囊,你不需要每次启动时手动激活安全功能。
技巧 4:--tmux —— 真正的并行会话
此前的“并行”通常是手动打开多个终端:终端 1 控制一个 worktree,终端 2 控制另一个,终端 3 操作主分支。虽然可行,但手动操作很麻烦。
--tmux 自动化了这一切:
| |
Claude Code 会创建一个 worktree,在 tmux 的一个面板中启动会话,然后将控制权返回给你的终端。你可以像这样启动三四五个会话:
| |
每个会话都有自己的 worktree,每个都运行在 tmux 的一个面板中,全部并行运行。你可以通过 Ctrl-b 加窗口号(或者你设置的 tmux 快捷键)在它们之间切换。
对于提高生产力来说,这就是 game changer。想象一下周一早上:你打开任务清单,选出三个独立任务,然后启动三个 agents。一个写测试,一个实现功能,另一个更新文档。你可以随时监督,检查 diffs,任务完成后合并分支。
这不是科幻,而是一个参数。
技巧 5:什么时候不应该使用 worktrees
知道什么时候使用 worktrees 很重要,但知道什么时候不该使用它们同样关键。Boris Cherny 明确指出了这一点,我非常同意。
不要在顺序性任务中使用 worktrees。 如果任务 B 依赖任务 A 的结果,并行化没有任何好处。实际上,你失去了效率:因为你需要在任务 B 开始前合并 A 的成果,这会比直接在同一个分支操作多出一个步骤。
不要为小改动使用 worktrees。 一行代码的小修改并不需要创建 worktree。即便 --worktree 已经将麻烦简化到一个参数,但同时管理多个活跃目录带来的心理负担是得不偿失的。
不要在修改同一文件时使用 worktrees。 如果功能 A 和功能 B 都会修改相同的 config.toml 或 routes.py 文件,不可避免会在合并时产生冲突。worktrees 的最佳用例是那些功能完全独立、不相互干扰的情景。
不要在没有计划的情况下使用 worktrees。 并行启动五个 agents“试试看”听起来很高效,但实际结果常常是:五个分支不知道状态如何,五个 diffs 等待检查,五个潜在的合并冲突。并行化的成功取决于明确的目标:清晰的任务、独立性及明确的验收标准。
黄金规则是:如果你能用一句话描述每个任务,并且它们之间相互独立,就使用 worktrees。如果不能,那还是串行处理吧。
完整工作流:把理论运用到周一早晨
为了让这看起来不那么抽象,请看我现在在处理任务清单时如何使用这个流程:
| |
以前,这些任务需要我一整个上午才能完成 —— 比如开发三个功能、写完测试并提交 PR。而现在,可以在去喝咖啡前搞定。
进化:从手动到原生支持
几周前,当我刚开始使用 worktrees 的时候,一切都得手动执行:git worktree add,cd,claude,打开一个新终端,再重复操作。这种方式虽然有效,但感觉就像每次想去院子晒太阳都要搭个帐篷。
有了 --worktree,isolation: worktree 和 --tmux,Claude Code 已经让 worktrees 像消失了一样存在。你无需操心如何管理它们,只需要说一声“开始并行”,工具就会为你搞定一切。
这就像容器技术的进化:一开始你得手动配置 LXC,后来 Docker 出现把一切抽象化,如今你几乎不用再想内核的 namespace 是怎么运作的。worktrees 已经走到了这种抽象阶段。Git 在 2015 年搭好了地基,十一年后相关工具终于让它们变得“不可见”。
这是我们对任何工具的最终要求:完成自己的工作,并从我们的视线中消失。
总结:Claude Code 面向 worktrees 提供了五大关键功能:--worktree(一键创建并进入 worktree)、隔离的子代理(每个代理拥有独立的工作区)、自定义 agents 的 isolation: worktree(隔离设计化)、--tmux(自动化并行会话)以及明确的使用场景。最终效果:无需手动管理的真正并行化。曾经被忽视的 git worktree,如今成了你使用 agents 流程中的“隐形基础设施”。