Codex

Codex App 多仓库项目怎么选目录、用 Worktree 并行任务

编辑部阅读约 6 分钟

微服务加前端的多仓库项目接入 Codex App 时,project 根目录该选单个仓库还是整个工作目录?并行任务为什么建议一任务一个 Git worktree?本文梳理 worktree 的机制、Codex 反复检查工作区导致改动被 reset 的风险,给出可照做的创建、隔离、合并流程与检查清单。

刚上手 Codex App 的人常常卡在同一个地方:手上的项目并非单一仓库,根目录下并排放着若干个微服务和一个前端工程;同时又看到「worktree」这个概念,听说可以并行跑多个任务,于是担心并行之后代码冲突不断、合并成本比省下来的时间还高。

这些顾虑大部分来自概念没对齐。worktree 是 Git 自带的能力,跟某个具体工具无关;而「一个任务一个 worktree」这种用法,背后有很实际的原因——不只是为了并行,更是为了隔离。下面把目录选择、worktree 机制、并行风险和处理流程拆开讲。

先弄清楚:worktree 到底解决了什么问题

普通开发中,切换分支是在同一个目录里完成的,git checkout 之后目录内容整体换掉。Git worktree 换了个思路:同一个仓库可以同时关联多个工作目录,每个目录检出不同的分支,互不干扰。

# 在当前仓库基础上,新建一个目录检出 feat/login 分支
cd ~/work/svc-order
git worktree add ../svc-order-login -b feat/login

# 查看当前仓库关联了哪些工作目录
git worktree list

执行后,~/work/svc-order-login 是一个独立目录,有自己的文件、自己的暂存区、自己的 git status,但提交历史与主仓库共享。这对 Codex App 这类工具的意义在于:每个 worktree 相当于一个干净、互不可见的沙盒,可以各开一个任务实例。

有两个 Git 层面的限制要记住:

  • 同一个分支默认不能在两个 worktree 里同时检出(除非强制),所以分支命名要区分开。
  • 依赖目录不会跨 worktree 共享。前端项目每个 worktree 都得重新装一次 node_modules,磁盘占用和安装时间都要算进去。

多仓库项目:project 该选单个仓库还是根目录

原则只有一条:project 根目录决定了 agent 默认看到什么、以及 Git 上下文从哪里取。所以要按「这次任务需要改几个仓库」来选,而不是按项目物理结构选。

场景 建议的 project 根 说明
任务基本落在单个服务内 该服务的仓库目录 Git 状态、worktree、提交都干净可追踪,最不容易出问题
一次改动横跨服务与前端(如改接口契约) 根目录,且根目录本身纳入版本控制 需要能同时看到多个仓库,但要额外约束 agent 的改动范围
根目录只是把若干仓库放在一起、本身无版本控制 仍选单个仓库 根目录下 Git 能力会退化,git status 看不到全貌,容易误判

如果确实要选根目录,务必在根目录放一份 AGENTS.md,写清三件事:各子目录分别是什么服务、本次任务允许改动哪些目录、提交时按仓库分别提交而不是在根目录一次性提交。

需要提醒的是,不同版本客户端对多仓库工作区的支持程度不完全一致,具体行为请以官方最新文档为准,先用一个只读的小任务验证一遍再放开手脚。

为什么强烈建议一个任务一个 worktree

这里有一个容易被忽略的坑,也是并行使用中最容易造成实际损失的地方:这类编码 agent 在工作过程中会频繁检查当前工作区的状态,判断「有没有多余文件、工作区干不干净」。

如果两个实例共用同一个工作目录,A 实例刚写好一半的文件,在 B 实例眼里就是「来路不明的未跟踪改动」。极端情况下,agent 为了让工作区恢复干净,可能执行 git reset 或 git restore,把另一个任务尚未提交的成果直接抹掉。这不是靠写几句提示词就能彻底杜绝的,属于模型行为习惯层面的问题。

worktree 从物理上消除了这种互相可见性:每个实例只看到自己的目录和自己的分支,git status 的结果永远只反映自己的改动。所以哪怕你并不打算并行,用 worktree 做一层隔离也是划算的。

反过来,如果只是想串行地做几件事,或者改动很小,那就在主工作区里老老实实一次跑一个任务,不必为了用 worktree 而用。

实操流程:从开任务到合并

步骤一:为任务建 worktree

cd ~/work/svc-order
git worktree add ../svc-order-feat-login -b feat/login
git worktree add ../svc-order-fix-timeout -b fix/timeout

目录命名带上分支语义,后面一眼能分清哪个目录对应哪个任务。

步骤二:在 worktree 里准备环境和 AGENTS.md

cd ../svc-order-feat-login
pnpm install        # 或其他包管理器,依赖不会共享

每个 worktree 内放一份简短的 AGENTS.md,明确边界,例如:

  • 本目录只负责订单服务的登录相关改动;
  • 不要修改 pnpm-lock.yaml,除非任务明确要求;
  • 不要执行 git reset --hard、git clean -fd、git restore .;
  • 完成后先跑 pnpm test,通过再提交。

这类约束能降低误操作概率,但不要指望它百分之百生效,物理隔离才是主要保障。

步骤三:把 Codex App 的 project 指到对应 worktree 目录

一个 worktree 对应一个 project 条目、一个任务实例,不要在同一目录里再开第二个实例。同时并行的任务数量建议控制在两到三个,多了之后合并成本上升得很快。

如果本地机器同时跑多个实例明显吃力,或者任务需要长时间挂着跑,可以把工作区放到一台长期在线的远程 Mac 上,本地只做连接和查看——新加坡的独享 Mac 属于这类可选方案之一,本质上解决的是设备性能和在线时长问题,跟 worktree 的正确用法无关。

步骤四:小步提交,及时合并

worktree 里的分支拖得越久,和主干的差距越大,冲突越难解。建议每完成一个可验证的小功能就提交一次,并尽快合回主干,而不是等所有并行任务都做完再一起合并。

冲突了怎么办:哪些能交给 agent,哪些不能

并行任务之间出现冲突是必然的,关键在于处理顺序:

  1. 先在 worktree 内完成自测并提交,保证该分支自身是完整可运行的状态;
  2. 回到主干 rebase 或 merge,让冲突暴露在一个明确的位置;
  3. 机械性冲突可以交给 agent:同一个文件不同区域的改动、import 顺序、格式化差异,让 agent 按上下文合并通常没问题;
  4. 语义冲突必须人来判断:同一段业务逻辑被两个任务改了不同方向、接口字段含义变化,这类冲突 agent 只能「让代码能编译」,无法保证行为正确;
  5. 合并后必须重新跑测试,冲突解决得漂亮不代表功能没坏。

一个实用习惯:合并前先看 git log --oneline main..feat/login 和 git diff main...feat/login --stat,确认这个分支到底改了什么,再决定是否交给 agent 处理。

清理:别忘了收尾

任务合并完成后,worktree 目录会一直留着,越积越多。定期清理:

git worktree remove ../svc-order-feat-login
git branch -d feat/login
git worktree list      # 确认剩余情况
git worktree prune     # 清理已被手动删除目录的残留记录

如果目录里有未提交内容,remove 会拒绝执行,这其实是个保护,先确认是否真的不需要了。

上手检查清单

  • 明确这次任务需要改几个仓库,再决定 project 根目录
  • 根目录若无版本控制,不要把它当 project 根
  • 一个任务一个 worktree、一个实例,不共用工作目录
  • 每个 worktree 单独装依赖,预留磁盘空间
  • 每个 worktree 内有约束性的 AGENTS.md,明确禁止破坏性 Git 命令
  • 分支命名带任务语义,避免与已有分支重名
  • 小步提交、尽早合并,不长期分叉
  • 合并后跑测试,再清理 worktree

小结

多仓库项目的目录选择,看的是这次任务跨几个仓库,而不是项目物理上长什么样;worktree 的价值首先是隔离,其次才是并行。把「一个任务一个干净工作目录」当成默认习惯,能规避掉大部分「改动莫名消失」和「并行后冲突解不完」的问题。至于客户端对多仓库的具体支持细节,各版本可能有差异,动手前先用一个小任务验证,以官方最新说明为准。

AGENTS.mdCodex AppGit Worktree多仓库项目并行任务