并行跑 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。
创建完成后,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 时分支保留,复杂合并回到终端显式处理。
可复用的五条原则
- 一个任务一个 worktree。 目录是并行任务的隔离边界,不是共享缓存。
- worktree 属于节点,不属于控制面。 多节点并行靠多个 clone,不靠共享目录。
- 分支名写清楚任务目标。 让 worktree、分支和任务能一一对应。
- 每个 worktree 单独验收。 测试、diff、提交和推送都按 worktree 走。
- 清理是流程的一部分。 先关会话、保持干净、再移除目录;分支是否保留由 Git 决定。
相关文档
- TaskHandoff 官网(产品定位与客户端下载):https://www.thandoff.com/
- 开源仓库:https://github.com/edgestorage/task-handoff
- 用 worktree 并行运行 AI 的完整教程:https://docs.thandoff.com/tutorials/worktree-session
- 仓库协作、变更、分支与远端同步:https://docs.thandoff.com/workspace/repository
- AI 会话与固定工作目录:https://docs.thandoff.com/sessions/
- 节点管理:https://docs.thandoff.com/admin/nodes
- 连接远程节点:https://docs.thandoff.com/integrations/remote-nodes
- 安装与部署:https://docs.thandoff.com/guide/install

