SkillHub 多 Agent 并行开发工作流:用 git worktree 隔离 Claude 与 Codex,安全合并与联调

原创2026-10-13 14:30:211,894 阅读
文章标签:AI 技能后端前端CLI认证鉴权搜索引擎

SkillHub 多 Agent 并行开发工作流:用 git worktree 隔离 Claude 与 Codex,安全合并与联调

导读

本文讲解 SkillHub 仓库推荐的 Claude + Codex 并行开发方案:为每个任务创建三个兄弟 git worktree,让两个 AI Agent 各自在独立目录写代码、互不覆盖,再由一个集成 worktree 统一合并并独占浏览器联调环境(http://localhost:3000)。读完本文,你将掌握 parallel-init / parallel-sync / parallel-up / parallel-down 四组命令的完整用法、底层脚本行为,以及一套"先隔离、后合并、再回归"的开 PR 流程。

适用前提:本文工作流面向 SkillHub 仓库本地开发场景,命令基于 Makefile 与 scripts/ 下的 bash 脚本;运行环境要求见 docs/dev-workflow.md(Docker、Java 21、Node.js 22 + pnpm、gh CLI)。

为什么需要并行工作流:核心规则

SkillHub 的开发经验表明,不要让两个 Agent 在同一份 checkout 上同时写代码——这是整个方案的唯一核心规则。Claude 与 Codex 如果指向同一目录,会互相覆盖文件、破坏对方的中间状态,使集成变得不可预测。

因此,每个任务固定使用三个兄弟 git worktree(彼此是平级目录,而非嵌套目录):

Worktree 目录命名 分支命名 职责
Claude 工作区 <repo>-claude-<task> agent/claude/<task> Claude 在此写代码
Codex 工作区 <repo>-codex-<task> agent/codex/<task> Codex 在此写代码
集成工作区 <repo>-integration-<task> agent/integration/<task> 合并结果、浏览器验证、最终回归

三条配套约定:

  • 只有 integration worktree 允许运行 make dev-all,从而让 http://localhost:3000(Web UI)与 http://localhost:8080(后端)始终反映合并后的最新特性,成为唯一事实来源;
  • 所有 worktree 共享同一套本地 Docker 依赖容器(Postgres、Redis、MinIO),make dev / make dev-all 复用同一批容器,避免多个 checkout 争抢端口;
  • 仓库仍保留 agent-worktrees、agent-sync 等旧别名作为兼容垫片,但规范化命令集是 parallel-init、parallel-sync、parallel-up、parallel-down。

一次性初始化:make parallel-init

在主仓库目录执行:

make parallel-init TASK=legal-pages

一次创建三个 worktree 与三条匹配的本地分支:

  • ../skillhub-claude-legal-pages(分支 agent/claude/legal-pages)
  • ../skillhub-codex-legal-pages(分支 agent/codex/legal-pages)
  • ../skillhub-integration-legal-pages(分支 agent/integration/legal-pages)

目录名中的仓库名取自 git common dir 的父目录(scripts/parallel-common.sh 中 repo_name() 函数),任务名会经 slugify() 统一规范为小写、以连字符分隔的 slug(tr '[:upper:]' '[:lower:]' 加正则清洗),因此 TASK 传 legal-pages、LegalPages 等写法都会被归一。

参数覆盖

# 指定基线分支与 worktree 落盘目录
make parallel-init TASK=legal-pages PARALLEL_BASE_REF=origin/main PARALLEL_WORKTREE_ROOT=/Users/wowo/workspace

# 若本工作流自身尚未合入 origin/main,则从当前分支派生
make parallel-init TASK=legal-pages PARALLEL_BASE_REF=HEAD

参数默认值与含义如下:

Make 变量 默认值 作用
TASK 必填 任务标识(slug),用于目录与分支命名
PARALLEL_BASE_REF origin/main 三个分支的派生基线 git ref
PARALLEL_WORKTREE_ROOT 主仓库父目录(dirname $(repo_root)) worktree 的落盘根目录

源码级行为

scripts/parallel-init.sh 的核心是 ensure_worktree()(第 32-58 行),对每个角色依次执行幂等检查:

  1. 目标目录已含 .git → 直接复用并提示"already exists",可安全重复执行;
  2. 目录存在但非 git worktree → 报错退出,避免覆盖普通文件夹;
  3. 分支已在其他 worktree 检出(branch_in_use() 通过 git worktree list --porcelain 检测)→ 报错,防止同一分支被两个 checkout 占用;
  4. 分支已存在(git show-ref --verify)→ git worktree add <dir> <branch> 关联已有分支;
  5. 否则 → git worktree add -b <branch> <dir> <base-ref> 从基线创建新分支。

脚本开头还会 git rev-parse --verify 校验 base-ref 确实存在,避免从一个不存在的 ref 派生。

责任分工:开工前先划分领地

文档建议在任一 Agent 开工前,把分工划分得粗粒度且明确:

  • Claude:需求分析、评审、文案、UI 结构、边界场景、回归评审;
  • Codex:实现、接线(wiring)、脚本、测试、重构、修复。

两条纪律:

  • 避免把同一个文件同时分配给两个 Agent;
  • 若某个文件必须由双方触碰,则对该文件改为串行编辑(一方完成并提交后,另一方再改)。

日常循环:实现 → 合并 → 验证

1. 并行实现

每个 Agent 只在被分配的工作区内工作:

  • Claude 在 ../skillhub-claude-<task>
  • Codex 在 ../skillhub-codex-<task>

各自独立提交自己的工作成果,提交后再进入集成,保证 integration 合并时拿到的是干净的 commit。

2. 合并进 integration

在 integration worktree 中一条命令完成"合并 + 启动":

cd ../skillhub-integration-legal-pages
make parallel-up

parallel-up 等价于按顺序执行两个步骤:先把默认源分支合并进当前 integration 分支,再以 make dev-all 启动集成环境。默认源分支为:

  • agent/claude/legal-pages
  • agent/codex/legal-pages

需要手动分步控制时,可以拆开执行:

cd ../skillhub-integration-legal-pages
make parallel-sync
make dev-all

两条命令都支持用 SOURCES 覆盖源列表:

make parallel-sync SOURCES="agent/claude/legal-pages agent/codex/legal-pages"
make parallel-up SOURCES="agent/claude/legal-pages agent/codex/legal-pages"

冲突处理:合并冲突一律在 integration worktree 内解决;除非有意重写该分支,否则不要在 Claude 或 Codex 的 worktree 里解决冲突。

3. 浏览器验证

只允许在 integration worktree 运行本地栈:

cd ../skillhub-integration-legal-pages
make parallel-up

然后验证合并结果:

  • Web UI:http://localhost:3000
  • 后端:http://localhost:8080

验证完成后收尾:

make parallel-down

命令背后的实现细节(源码级)

四个命令在 Makefile 第 385-399 行定义,实际逻辑落在 scripts/ 下四个脚本中:

parallel-sync(scripts/parallel-sync.sh)

  • 任务名可通过参数传入,也可从当前分支自动推断(require_integration_task() 要求当前分支匹配 agent/integration/<task> 前缀,见 scripts/parallel-common.sh);
  • 执行前强制校验 integration worktree 位于正确的 integration 分支,且工作树必须干净(require_clean_worktree() 检查 git diff 与 git diff --cached,第 31-36 行);
  • 每个源分支先做 git rev-parse --verify 存在性检查,再依次执行 git merge --no-ff --no-edit(第 76-82 行);任一合并失败即报错退出并提示在 integration worktree 手动继续。

parallel-up(scripts/parallel-up.sh)

  • 先以 PARALLEL_WORKTREE_ROOT 环境变量透传调用 parallel-sync.sh,合并完成后在 integration 目录执行 make -C <dir> dev-all(第 45-47 行),并打印 Web UI / 后端地址。

parallel-down(scripts/parallel-down.sh)

  • 同样要求从 integration 分支运行(require_integration_task),随后执行 make -C <repo> dev-all-down(第 23-27 行),即停掉后端与前端进程并 docker compose down --remove-orphans 回收依赖容器(见 Makefile 第 159-162 行 dev-all-down)。

依赖容器共享原理:所有 worktree 能共用一套容器,关键在于本地开发环境固定了 Docker Compose 项目名——Makefile 中 DEV_COMPOSE_PROJECT_NAME ?= skillhub,make dev / make dev-all 一律以 docker compose -p skillhub 操作。因此无论从哪个 worktree 启动,Postgres(5432)、Redis(6379)、MinIO(9000/9001)、skill-scanner(8000)都命中同一批容器,多个 checkout 不会互相争抢端口;详见 docker-compose.yml 与 docs/dev-workflow.md 第 27 行的说明。

验证清单(开 PR 前)

从 integration 分支发起 PR 之前,按文档建议依次完成:

  1. 先做最小验证:例如 pnpm --dir web typecheck 或后端测试;
  2. 在 integration worktree 执行 make parallel-up;
  3. 在 http://localhost:3000 验证最终合并行为;
  4. 若变更涉及 Docker 路径或需要 smoke test 信心,执行 make staging(该目标会构建后端镜像与前端静态文件、启动混合 staging 环境并运行 scripts/smoke-test.sh,见 Makefile 第 311-337 行)。

恢复规则

  • 某个 Agent 分支方向走偏:只在该分支自己的工作树内 reset 或丢弃该分支;
  • integration 变乱:从原始基线仅重建 integration 分支,再重新合并;
  • 端口被占用:确认没有任何 Claude / Codex worktree 在运行自己的本地栈(端口唯一归属 integration)。

PR 策略

两种安全做法任选其一:

  1. 合并验证通过后,直接从 integration 分支开 PR;
  2. 或把验证过的 commit cherry-pick 到一条干净的特性分支,再从该分支开 PR。

对该仓库而言,文档推荐的最简路径通常为:

# 1. Claude 分支提交
# 2. Codex 分支提交
cd ../skillhub-integration-legal-pages
make parallel-up          # 3. 合并并启动集成环境
# 4. 在 http://localhost:3000 验证
# 5. 从 integration 分支开 PR

命令速查

# 一次性初始化(主仓库目录执行)
make parallel-init TASK=legal-pages
# 进入集成工作树,合并 + 启动 + 验证
cd ../skillhub-integration-legal-pages
make parallel-up
open http://localhost:3000
# 完成后停止联调环境
make parallel-down

完整流程总览

make parallel-init TASK=<task>     # 建三个 worktree:claude / codex / integration
├─ Claude 只在 ../skillhub-claude-<task>  编码并提交
├─ Codex 只在 ../skillhub-codex-<task>    编码并提交
└─ integration worktree:
   make parallel-up                 # 合并两分支 + make dev-all(唯一联调入口)
   http://localhost:3000            # 浏览器验证合并结果
   make parallel-down               # 停止栈
make staging                        # (可选)Docker 路径回归
make pr                             # 从 integration 分支发起 PR

这套工作流把"两个 Agent 并行写代码"从互相踩踏的混乱状态,收敛为"目录隔离 + 分支隔离 + 单一集成事实源"的可预测流程;命令全部由 scripts/parallel-*.sh 幂等实现,可随时重复执行、安全恢复。

登录后查看全文
skillhub