← 返回 蓝图示意图,显示两条并行管道从一个源分支出来,再合并回单个输出,代表隔离的并行 git worktrees

Claude Code Worktrees:并行任务,零文件冲突

逐个运行 Claude Code 会话是一种习惯,而不是必需。当你的任务真正独立时,没有理由一个必须等待另一个。Git worktrees 为每个 Claude 会话提供自己的检出目录和自己的分支,所有这些都来自同一个 .git 对象库。没有重复克隆,没有文件冲突,完成时用标准的 git merge。本文讲解完整的工作流:何时需要 worktree、如何设置、你实际获得了什么隔离(以及什么没有),以及如何清理而不丢失尚未提交的工作。

何时 Worktree 有帮助

不是每个任务都需要。老实说:worktrees 在相当具体的几种情况下大放异彩。

YouTube 上 bri 的演练视频(2026 年 6 月)说得很好。当你有两个或多个不共享同一文件的任务时使用 worktree,或者当一个任务风险足够大,你想在提交到任何一个之前看到两个不同的方法时。如果单个任务跨越整个代码库,坚持一个会话。探索性工作也是如此,你希望代理自由漫游。

另一个好用例:推测性工作。启动三个 worktrees,为同一个问题给每个略微不同的提示,然后选择你喜欢的版本。Zylos Research 指出,这种模式在运行四个或更多并发 AI 会话的团队中变得普遍,正是因为你在对冲非确定性模型输出而不是依赖单次运行。

反之,如果你的项目涉及大型 TypeScript monorepo、PostgreSQL、Redis、多个内部包和 Remix 前端,worktrees 单独不会解决你的协调问题。Trigger.dev 写过正是这个问题,最终转向了不同的方法。文件系统隔离是真实的。服务隔离不是自动的。

创建隔离的任务检出

从你的基础分支开始并拉取最新版本。然后将 .claude/worktrees 添加到你的 .gitignore 一次:

echo ".claude/worktrees" >> .gitignore

Claude 默认将 worktrees 放在你的仓库目录内。没有那个 .gitignore 条目,它们会显示为未跟踪的文件并杂乱你的 git status。添加它、提交它、忘记它。

现在为每个任务启动一个会话。打开两个终端:

claude --worktree feature-payments

``

claude --worktree bugfix-auth

根据 Dan Does Code 的文章,Claude 在 .claude/worktrees/feature-payments/ 创建 worktree,检出一个新分支,并将会话限定到那个目录。你的主工作树在整个过程中保持不变。你也可以使用短标志形式 claude -w feature-payments 如果你愿意的话。跳过名称,Claude 会自动生成一个。

每个会话现在在完全的文件系统隔离中运行。终端 1 中的代理无法触及终端 2 中的代理正在处理的文件,因为它们在不同目录上的不同分支中。这就是全部技巧。这是基础设施级别的分离,而不是代理之间的协调逻辑。(如果你想要的是那样,Claude Code subagents 指南涵盖了编排方面。)

为每个会话分配其任务

一旦两个会话都在运行,为每个分配其指令。把每个 Claude 实例当作一个新的上下文。要具体说明范围。如果终端 1 在构建支付功能,告诉它要接触哪些文件和要留下哪些文件不动。终端 2 也一样。

会话结束时,在关闭终端前让 Claude 推送分支并开启拉取请求。这样代码工作就安全地离开了本地机器,准备好被审查。

管理依赖、端口和本地配置

这是事情变得复杂的地方。文件系统隔离是自动的。其他一切都需要一些手动设置。

两个独立齿轮组件共享中心轴的蓝图,代表共享存储库元数据的独立工作树环境

端口。如果两个工作树都启动开发服务器,默认情况下会在同一个端口上产生冲突。解决办法是给每个工作树一个自己的 .env 文件,分配不同的端口。比如一个设置 PORT=3001,另一个设置 PORT=3002。或者在启动时通过命令行参数传入覆盖值。两种方式都行得通。

数据库。SQLite 很简单:让每个工作树的 .env 指向不同的文件路径。PostgreSQL 或 MySQL 需要更多考虑。你需要每个工作树一个独立的数据库实例,或至少在同一实例内有独立的 schema/数据库。通过每个工作树的 .env 中的环境变量配置连接字符串。不要在两个代理并发写入迁移时共享同一个数据库。那样会导致数据损坏或竞态条件。

本地配置文件。如果你的项目使用了未提交的本地配置文件(比如 .env.local、config/local.yml),你需要为每个工作树创建一个。它们不会从主工作树自动继承。

MindStudio 关于并行 AI 编码代理的指南涵盖了更多这些隔离模式的细节。简而言之:工作树在设计上就提供了分支和目录隔离。数据库和端口隔离需要你提前显式配置。

还有一件值得指出的事。如果你在做一个需要复杂或昂贵本地服务设置的项目,同时运行多个工作树,要考虑设置成本是否值得并行加速。对于库或 CLI 工具,绝对值得。对于拥有六个服务的完整堆栈单体仓库,也许就不那么划算。如果你想要帮助评估,Claude Code 开发者可以判断工作树还是其他并行策略更适合你的堆栈。

审查并整合两个分支

两个代理都完成了。两个分支都推送了。现在该审查了。

这里的工作流是标准的 git。并行设置不会改变合并流程。一个典型的两任务仓库的编号序列:

  1. 检出 main 并拉取最新更改。
  2. 审查第一个分支。git diff main..feature-payments 可以看到完整的变化情况。
  3. 如果你对它满意,合并或变基到 main。用通常的方法解决与基础分支的任何冲突。
  4. 再次拉取 main 以获得这些变化。
  5. 审查第二个分支。git diff main..bugfix-auth
  6. 合并。如果两个代理修改了重叠的文件(按理不应该在任务范围正确时发生,但有时会),在这里解决冲突。
  7. 两个合并都完成后,对 main 运行你的测试套件。

按这种方式逐个审查而不是同时合并两个的好处是,一个合并产生的冲突不会叠加到下一个。差异更简洁,推理更容易。

清理而不丢失未提交的工作

清理是开发者感到紧张的地方。如果工作树中有从未提交的工作怎么办?

答案是:在移除工作树前把它贮存起来。

如果你在某个工作树中有未提交的改动想要保留,请进入该工作树目录并运行:

git stash push -m "wip: payments feature - pre-cleanup"

这个存储位于共享的 .git 对象库中,这意味着在删除原始工作树后,它可以从你的主工作树或任何其他工作树访问。存储完成后,你可以安全地删除:

git worktree remove .claude/worktrees/feature-payments

然后,回到你的主工作树,弹出存储:

git stash pop

如果实验完全失败,你想从中什么都不要,直接删除而不用存储。git worktree remove 加上 --force 标志会删除工作树,即使它有未提交的改动。使用 --force 前要三思。没有恢复路径。

删除所有工作树后,清理列表以保持整洁:

git worktree prune

这会从 .git/worktrees/ 中删除任何陈旧的管理引用。

工作树不隔离的共享资源

有必要明确说明这一点,因为"隔离"的心智模型可能会误导你。

工作树隔离的内容:

  • 工作目录及其中的所有文件
  • 每个会话操作的分支
  • 暂存和未暂存的改动

工作树不隔离的内容:

  • .git 对象库(按设计共享)
  • 机器本地自动内存(官方内存文档确认同一仓库的工作树共享这个)
  • 外部服务:数据库、队列、缓存、任何网络依赖
  • 环境凭证和 API 密钥,除非你显式为每个工作树设置不同的值
  • 两个会话继承的操作系统级 Shell 环境中的任何内容

这对安全性也很重要。工作树不是租户边界。如果两个会话共享相同的 API 密钥或数据库凭证,它们会共享访问权限。不要把工作树当作将 Claude 会话与敏感本地配置隔离的方式。它不是这样的。

如果要在更广泛的工作流中编排多个代理而不仅仅是文件系统隔离,Claude Code 超能力帖子会深入讲解更广泛的模式。

FAQ

`claude --worktree` 的工作原理是否与手动运行 `git worktree add` 相同?

功能上相似但不完全相同。claude --worktree 执行 git worktree add、创建分支,并在一步内将 Claude 会话限定到该目录。如果你手动运行 git worktree add 然后在生成的目录内启动 Claude,你会得到相同的文件系统结果,但没有 Claude 的内置限定。对于常见情况,--worktree 标志是更快的路径。

我能同时运行两个以上的工作树吗?

能。git 或 Claude Code 对工作树数量没有硬限制。实际限制是你机器的 RAM 和 CPU。每个 Claude 会话是一个单独的进程,有自己的上下文。在现代开发机器上同时运行三四个会话是可以的。超过这个数量,你可能会先遇到资源限制,而不是 git 限制。

如果我删除 worktree,该 worktree 的分支会怎样?

分支会保留下来。git worktree remove 会删除工作目录和 .git/worktrees/ 中的管理引用。分支本身保持不变,可从你的主工作树或任何其他 worktree 访问。当你不再需要该分支时,可以用 git branch -d branch-name 单独删除它。

Worktree 会影响 Claude 读取或写入 `CLAUDE.md` 项目记忆的方式吗?

同一仓库的 worktree 根据官方记忆文档共享机器本地的自动记忆。如果你在仓库中提交了 CLAUDE.md 文件,每个 worktree 都从自己的检出副本中读取它。一个代理在其 worktree 中对 CLAUDE.md 所做的编辑在合并前仅限于该分支。但机器本地层是共享的,所以一个会话写入的指令对另一个会话是可见的。

运行 worktree 相比单独克隆有性能成本吗?

Worktree 比克隆便宜。它们共享 .git 对象存储,因此磁盘上不会重复整个仓库历史。主要成本是工作目录本身,即分支当前状态下所有受跟踪文件的完整检出。对于包含二进制资产或生成文件的大型仓库,检出大小会累加。但 git 操作(fetch、log、diff)都针对单个对象存储运行,因此速度很快。

选择 worktree 而非单独克隆的最简洁理由是:在一个 worktree 中创建的 stash 和 ref 在同一仓库的其他地方立即可访问。这种共享状态正是上面清理工作流能够工作的原因。

← 返回