并行跑 AI 任务,常见的阻碍往往不是模型能力,而是目录。

两个会话在同一个工作目录里改代码,A 刚写完的文件可能被 B 覆盖;你打开文件准备保存,界面提示版本已经过期;测试失败时,也很难判断是哪一个任务改坏的。机器一多,问题还会多一层:任务到底跑在哪台服务器、哪个目录、哪个分支?

Git worktree 能解决其中一部分问题,但它不是「把同一个目录挂到多台机器」的魔法。这篇讲清楚 TaskHandoff 里的分工方式:一台节点、一份仓库 clone、一个任务、一个 worktree,以及多节点时哪些事情不能做。

先说结论:多节点并行不是共享一个 worktree

Git worktree 是同一个仓库的独立工作目录和分支。它让多个会话各自拥有一个目录,减少并行编辑冲突;但 worktree 仍然属于某一台机器上的某一个仓库 clone。

所以多台远程服务器并行跑任务时,正确模型是:

同一远端仓库 ├── 节点 A 的 clone → worktree A-1(分支 feature/a) └── 节点 B 的 clone → worktree B-1(分支 feature/b) 

不是:

节点 A 的 worktree ← 同时挂给节点 B 的会话 

前者是多个独立 checkout,后者会制造路径、锁和文件一致性问题。TaskHandoff 的多节点模型按节点管理实例和会话,不把 worktree 当成跨节点共享目录;它做的是把多个节点、多个实例和多个会话放进同一个控制面里查看和操作。

为什么不用同一个目录硬跑

在同一台机器上,两个 Codex 或 OpenCode 会话共用一个工作目录,至少会遇到三类问题:

  • 文件互相覆盖:两个任务同时改同一个文件,后写入的版本不一定是你想要的。
  • 状态难以归因:测试失败、依赖变化、未跟踪文件,分不清来自哪个任务。
  • 保存冲突:文件被 AI、终端或另一个编辑器改过后,保存会因版本过期停止,需要先比较再决定。

worktree 把「任务」和「目录」绑定起来:一个任务一个目录,一个目录一个分支。这样每个任务的变更、测试和提交都能独立检查。

做法:一台节点,一个任务,一个 worktree

下面是一条可复用的路径。它不是通用答案,但边界比较清楚。

1. 把远程服务器接成节点

节点是运行 Node Agent、并实际管理实例的计算机。打开「设置 → 节点 → 添加节点」,根据网络条件选择连接方式。远程节点通常用反向 WSS:Node Agent 主动连 Control Plane,不需要给节点开放公网入站端口。

一次性加入 Token 只用于首次建立信任,配对完成后不要把它写进脚本仓库、工单或日志。

2. 在每台节点上创建 Git 实例

每台要参与并行的服务器,各自创建自己的 Docker 实例,并把同一个远端仓库 clone 进来。多节点不是共享工作区,而是每台机器保持自己的 clone。

如果你需要控制 Git 权限,凭据按 remote scope 匹配;HTTPS token 只在 credential-helper 请求期间短暂提供,不写进 remote URL、命令行或环境变量。SSH 私钥留在 Node Agent,实例只拿签名能力。

3. 从已有 Git 会话创建托管 worktree

打开已有 Git 会话的「环境 → 工作树」,选择「新建托管工作树 AI 会话」,填写新分支名称和起始引用,再选择 Codex 或 OpenCode。

新建 AI 会话时选择 Agent、模型和工作目录

创建完成后,TaskHandoff 会生成托管 worktree 和新会话;原会话仍停留在原来的工作目录。会话创建后工作目录不会自动改变,所以换 worktree 的正确做法是「在目标 worktree 上新开会话」,不是把当前会话挪过去。

4. 在另一台节点重复,而不是复制目录

第二台服务器也按同样方式创建自己的实例、clone 和 worktree。两个 worktree 可以在同一个远端仓库上使用不同分支,但它们在文件系统上彼此独立。

建议把分支名和任务目标绑定,例如 feat/api-timeout、fix/windows-paths。不要让两个会话在同一个 worktree 同时修改相同文件;如果一个任务需要改同一批文件,先拆任务,或者让它们串行。

5. 分别在每个 worktree 里审阅、测试、提交

每个 worktree 都有自己的变更集。分别检查测试和 diff,确认后再提交和推送。TaskHandoff 的远端操作是保守的:Pull 仅允许 fast-forward,不自动 merge、rebase 或 stash;分支分叉时阻止自动同步;永远不 force push。

复杂冲突、已分叉分支、大型或二进制 diff,建议到对应会话的终端里处理,然后刷新仓库页面。

多节点时,节点选择看什么

节点不是越多越好。比较实际的分配依据是:

  • 运行时和依赖:哪台机器有项目需要的 Docker 镜像、系统工具或 GPU。
  • 隔离边界:不同客户、不同仓库、不同权限的凭据是否应该落在不同节点。
  • 网络位置:节点在公司内网、家用服务器还是云主机,决定了它能不能访问目标仓库和依赖。
  • 任务时长:长任务放在常开的服务器上,临时任务放在随手可用的节点上。

不要为了「看起来并行」把同一个 worktree 复制到多台机器。复制目录会带来身份、缓存和未跟踪文件的不一致;正确做法是每台节点从远端仓库创建自己的 checkout。

交付和清理:分支保留,目录才删除

托管 worktree 由 TaskHandoff 创建,可以安全地用于新 AI 会话。外部 worktree 只有位于实例授权目录且仍可访问时才能使用,系统不会接管或删除它。

删除托管 worktree 前,它必须是非主工作树、无修改、未锁定,并且没有活跃的 AI 或应用会话。删除的是工作树目录,关联的 Git 分支会保留;系统使用非 force 删除,不会顺手删掉你的分支。

主工作树、外部 worktree、有未提交修改或仍被活跃会话占用的 worktree,不能从界面删除。这条限制看起来麻烦,但它防止的是「清理目录时把正在跑的任务或未提交改动一起弄丢」。

踩坑:四个容易犯的错

把 worktree 当成跨机器共享目录。 它不是。多节点并行是多个 clone、多个 worktree,不是一个目录挂给多台机器。

两个会话共用一个 worktree。 文档明确建议并行任务分配不同 worktree;同一 worktree 里的两个会话会看到彼此写入磁盘的修改。

在主工作树上直接开长任务。 主工作树通常承载你正在做的改动。更稳妥的方式是从它创建托管 worktree,把实验性任务放到独立目录和分支。

以为移除 worktree 会删分支。 移除的是目录,Git 分支保留;但目录里有未提交修改或仍有活跃会话时,系统会阻止删除。

结果:行为上发生了什么变化

  • 两台服务器上的任务出现在同一个控制面里,可以按节点、项目、状态查看。
  • 每个任务有自己的目录和分支,文件冲突不再靠人肉记忆避免。
  • 每个 worktree 单独测试、审阅、提交,失败时更容易归因。
  • 清理 worktree 时分支保留,复杂合并回到终端显式处理。

可复用的五条原则

  1. 一个任务一个 worktree。 目录是并行任务的隔离边界,不是共享缓存。
  2. worktree 属于节点,不属于控制面。 多节点并行靠多个 clone,不靠共享目录。
  3. 分支名写清楚任务目标。 让 worktree、分支和任务能一一对应。
  4. 每个 worktree 单独验收。 测试、diff、提交和推送都按 worktree 走。
  5. 清理是流程的一部分。 先关会话、保持干净、再移除目录;分支是否保留由 Git 决定。

相关文档