mcpField
M
merge-orchestrator

merge-orchestrator

github.com/lvlup-sw开发22128 次安装1 天前更新
代码仓库

关于 merge-orchestrator

面向 Exarchos 工作流的本地 Git 分支合并技能。它通过预检、记录恢复点和失败恢复处理合并;共享集成分支须经串行租约路径合并。

主要功能

  1. 01使用指定策略合并本地分支
  2. 02预检工作树与分支状态
  3. 03合并前记录恢复点
  4. 04失败时恢复且不执行硬重置
  5. 05支持结构化事件与阶段续跑

适用场景

  1. 01本地合入子 Agent 工作树分支
  2. 02串行合并到共享集成分支
  3. 03失败后恢复目标分支

MCP 相关

通过 Exarchos MCP 编排操作执行并跟踪本地合并;共享集成分支使用 serialize_merge 获取单写者租约。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lvlup-sw/exarchos --skill merge-orchestrator

安装后在 Claude Code 中输入/merge-orchestrator确认已加载。

附带文件references/local-git-semantics.mdreferences/recovery-runbook.md

详细介绍

合并编排器技能

本地 Git,而非远程 VCS

此技能会在本地执行 git merge,将源(子 Agent)工作树分支合并到目标(集成)分支,并记录一个恢复点 SHA,以便在发生任何故障时,按照 INV-14 恢复阶梯(git merge --abort → git reset --keep,绝不使用 --hard)回退合并。它不会调用 VCS 提供商(GitHub / GitLab / Azure DevOps),也不需要 PR id。有关远程 PR 合并,请参阅封装 merge_pr 操作的配套技能。

关于这两项关注点为何需要分别处理的思路模型和原因,记录在 references/local-git-semantics.md 中。

单写入者入口点:serialize_merge

对于共享集成分支——在 delegate → merge-pending → delegate 循环期间,将子 Agent 工作树分支合入集成 ref,而此时同级工作树的合并可能发生竞争——serialize_merge 是集成合并的唯一入口。它会获取按 integrationRef 隔离的乐观租约(每个集成 ref 至多允许一个正在进行的合并),然后在该租约下原样组合执行此操作。集成分支合并必须通过 serialize_merge 路由;不要为此直接调用原始 merge_orchestrate。

只有在目标上不会发生并发合并竞争时,才可直接调用 merge_orchestrate:

  • 非集成合并——目标是私有 / 临时 / 独立分支,不会被其他 Agent 操作。
  • 崩溃后恢复的调用方——新的 pid 完成其已获取租约的合并,并重新提供原始请求中的 leaseOperationId。
  • 组合执行器调用——serialize_merge 自行发起的调用(它会传递自己的租约 operationId,使其调用通过检查)。

DR-2 租约防护。如果针对集成 ref 的原始 merge_orchestrate 调用遇到一个有效的他方租约(持有者的 operationId ≠ 所提供的 leaseOperationId,且持有者状态 ∈ {alive, unknown}),则会安全失败,返回结构化的 MERGE_LEASE_HELD 错误,且不会产生任何 git 副作用;错误消息会指出应使用 serialize_merge。如果没有租约,或可确认持有者已死亡,则会照常继续(向后兼容;已死亡的持有者不会构成阻碍)。因此,这些路由要求由处理器的关键入口强制执行,而不只是约定俗成——请使用 serialize_merge。

概述

每当操作员(或自动化的 next_actions 分发器)针对 Exarchos MCP 调用 merge_orchestrate 操作时,此技能就会启用。源分支在工作树中准备完毕后,此技能会:

  1. 执行工作树可用性预检(目标分支不得在同级工作树中处于检出状态)。
  2. 组合执行其他预检防护(祖先关系、当前分支保护、主工作树断言、工作树漂移)。
  3. 将目标分支合并前的 HEAD 记录为恢复点(写前日志标记,在任何 ref 修改前持久化)。
  4. 在本地将源分支 git merge 到目标分支。
  5. 发生任何故障时,执行 INV-14 恢复阶梯(git merge --abort → git reset --keep <recoveryPointSha>,绝不使用 --hard),并给出分类后的失败原因。
  6. 发出专用事件类型,使合并时间线仅凭事件日志即可重建。

支持恢复续行:在重新进入时,终结阶段(completed / rolled-back / aborted)会短路退出,不会重复发出事件。支持幂等:使用相同 taskId 重新分发时,会通过 next_actions 幂等键合并为同一次操作。

触发条件

在以下情况下激活此技能:

  • 操作者运行 exarchos merge-orchestrate ...(CLI)。
  • 直接调用 exarchos:exarchos_orchestrate({ action: "merge_orchestrate", ... })。
  • 自动化 next_actions 信封为 merge-pending 分流显示了合并动词(幂等键 <streamId>:merge_orchestrate:<taskId>)。

通过 serialize_merge 路由共享集成合并。 如果触发条件是共享集成分支(常见情况是 merge-pending 分流),请按照上文的单写入者入口,通过 serialize_merge 执行合并——serialize_merge 会在租约下组合此操作。直接原始分发 merge_orchestrate 仅适用于非集成合并或已持有租约的合并;若针对已租赁的集成引用执行,则会安全失败(MERGE_LEASE_HELD)。

不要在以下情况下激活此技能:

  • 合并远程 PR——应使用 merge_pr。这两种操作互不相关;请参阅下文的消歧说明。
  • 编排器记录的 mergeOrchestrator.phase 已处于终态——恢复短路机制会运行,但无需进行新的分发。

流程

架构: 使用 exarchos:exarchos_orchestrate({ action: "describe", actions: ["merge_orchestrate"] }) 获取此操作的参数架构。策略为必填项(架构层面没有默认值)——请审慎选择 squash / merge / rebase。

步骤 1:选择合并策略
策略本地 git 操作选择时机
mergegit merge --no-ff --no-edit <source> — 显式合并提交保留子 Agent 的提交历史,并显示清晰的合并边界。
squashgit merge --squash <source> 然后执行 git commit — 在目标分支上生成单个压缩提交子 Agent 的提交历史过于冗杂;一项逻辑变更应作为一个提交合入。
rebase将源分支的临时副本变基到目标分支上,然后对目标分支执行快进合并 — 线性历史不生成合并提交;集成分支保持线性。原始源引用会保留(变基在临时分支上执行,之后会删除该分支),因此执行器恢复时只需将目标分支回退到恢复点。

策略在架构层面为必填项(用于冲突检查和用户可见的一致性)。没有隐式默认值——操作者的意图始终会明确记录在事件日志中。

步骤 2:调用

集成合并? 下方的直接调用是原始执行器形式——仅用于非集成合并或已持有租约的合并。对于共享集成分支,请改为调用 serialize_merge(它会在单写入者租约下组合执行完全相同的调用);请参阅上文的单写入者入口。

通过 MCP 调用(示例——规范参数名称以 describe 返回的结果为准):

exarchos:exarchos_orchestrate({
  action: "merge_orchestrate",
  // workflow-correlation identifier — name per the action's schema
  sourceBranch: "<subagent-branch>",
  targetBranch: "<integration-branch>",
  taskId: "<task-id>",          // present when auto-dispatched from next_actions
  strategy: "squash",            // required
  dryRun: false,                 // optional — preflight only, no executor invocation
  resume: false,                 // optional — short-circuit on terminal phases
})

通过 CLI 调用:

exarchos merge-orchestrate \
  --source-branch <subagent-branch> \
  --target-branch <integration-branch> \
  --task-id <task-id> \
  --strategy squash
  # plus the workflow-correlation id flag — see `--help`
  # add --dry-run for preflight-only, --resume for terminal-phase short-circuit

CLI 退出代码:0 = 成功,1 = 输入无效,2 = 合并失败(预检阻止或已执行恢复),3 = 未捕获的异常。

第 3 步:解读结果

处理程序会返回一个 ToolResult,其 data.phase 用于区分结果:

phase含义操作者操作
completed本地合并已完成;mergeSha 是目标分支的新 HEAD。无——工作流按编排器的操作手册继续执行。
aborted预检失败;未尝试合并。data.preflight 包含结构化的防护子结果(如果由正文预检生成),或者 data.reason 用于区分提前中止的原因。请参阅下方的中止原因表。解决根本问题后重新分派。
rolled-back已尝试合并,但失败(reason: 'merge-failed' / 'verification-failed' / 'timeout'),并执行了 INV-14 恢复流程(git merge --abort → git reset --keep <recoveryPointSha>)。目标分支已回退到恢复点。(阶段值仍为 rolled-back——这是一个关键状态令牌,不会因恢复框架的调整而改变。)检查 data.reason。如果还存在 data.recoveryError / data.recoveryErrorDetail,则重置本身也失败了——工作树处于受困状态,需要操作者介入。
中止原因的载荷格式

当 phase === 'aborted' 时,数据载荷会区分具体原因:

data.reason载荷字段原因操作者补救措施
target-checked-out-elsewheresiblingWorktreePath: string(绝对路径)目标分支已在同一仓库的另一个工作树中检出。此情况会在工作树可用性预检期间检测,早于任何事件发出、执行器调用或状态持久化。解决该工作树问题:移除它(git worktree remove <path>)、将其检出切换到其他分支,或针对其他目标重新运行合并。然后重新分派(共享集成引用时通过 serialize_merge 执行)。
(正文预检失败)data.preflight: { ancestry, worktree, currentBranchProtection, drift }正文预检防护失败(祖先不匹配、工作树漂移、当前分支受保护等)。检查 preflight.* 子结果,确定失败的防护项。解决根本问题(例如,提交或暂存状态漂移、切换离开受保护分支),然后重新分派。

target-checked-out-elsewhere 中止路径比较特殊:它会同时抑制 merge.requested 和 merge.preflight 事件,并完全跳过状态持久化。这可确保事件日志不会记录无法捕获正确恢复点的尝试(执行器会从错误的工作树读取 HEAD)。

有关各结果对应的完整恢复流程,请参阅 references/recovery-runbook.md。

步骤 4:确认事件发射

事件会直接发射到编排器的事件流(流 ID 是传入的 streamId 值)——不会包装在 gate.executed 中:

事件类型时机携带内容
merge.preflight始终发射(预检运行后、任何合并尝试前)——但提前中止的 target-checked-out-elsewhere 路径除外,该路径不会发射任何事件完整的结构化防护子结果,以及 passed: false 时的 failureReasons
merge.requested预检通过后、执行器运行前(双事件拆分中的 A 阶段意图记录)——提前中止的 target-checked-out-elsewhere 路径会抑制此事件sourceBranch、targetBranch、strategy、taskId
merge.executed本地合并成功时mergeSha、rollbackSha、taskId、源分支/目标分支
merge.recovered合并后发生故障并随后恢复时——这是规范的恢复事件,自 DR-2 起也是唯一会发射的恢复事件recoveryPointSha、reason、recoveryError?、recoveryErrorDetail?、taskId、源分支/目标分支
merge.rollback已弃用(DR-2)——旧版线格式,兼容读取但不会发射:现在已没有任何代码会写入此事件;它只保留在 DR-2 之前的事件日志中,并与 merge.recovered 一样折叠处理rollbackSha、reason、taskId、源分支/目标分支

恢复术语。 规范的框架基于数据库事务,而非 Saga:恢复点(记录的 HEAD SHA,在合并前作为预写日志标记持久化)和恢复事件(merge.recovered)。merge.recovered 是 merge.rollback 的后继事件,自 DR-2 起也是执行器发射的唯一恢复事件;旧版 merge.rollback 写入路径已弃用(兼容读取但不会发射,仅为确保 DR-2 之前的日志可被同样地重放而保留)。merge.recovered 携带已确定的 recoveryPointSha / recoveryErrorDetail 字段名,以及未变更的 INV-14 recoveryError 判别字段;保留的 merge.executed 事件仍携带其 rollbackSha 线字段。阶段值 'rolled-back' 有意保留。

这些事件由处理程序自动发射——正常操作时,不要通过 exarchos:exarchos_event 手动追加这些事件。只有在 recovery-runbook.md 中记录的手动恢复流程里,才允许手动发射:当合并已在外部完成(例如,冲突解决),且事件日志必须恢复同步时,请遵循该运行手册中以事件优先的顺序。

通过 exarchos:exarchos_event({ action: "describe", eventTypes: ["merge.preflight", "merge.requested", "merge.executed", "merge.rollback", "merge.recovered"] }) 发现事件负载架构。(merge.rollback 是旧版、兼容读取的事件——为确保 DR-2 之前的日志可被重放而保留,现已不再发射。)

消除歧义:merge_orchestrate 与 merge_pr

两个相关操作,各自关注点不同:

方面merge_orchestrate(此技能)merge_pr(配套技能)
层级本地 SDLC 交接远程 PR 基元
合并内容子 Agent 工作树分支合并到目标分支通过 VCS 提供商 API 合并面向用户的 PR
所需标识符sourceBranch + targetBranchprId
底层操作git merge(本地)provider.mergePr()(远程 API)
恢复INV-14 恢复阶梯:git merge --abort → git reset --keep <recoveryPointSha>(实际执行,回退合并;绝不使用 --hard)无——VCS 提供商拥有合并状态
事件merge.preflight / merge.requested / merge.executed / merge.recovered(旧版 merge.rollback 已弃用——兼容读取,不会发射)pr.merged

如果你想到“我想合并一个 PR”而去使用 merge_orchestrate,那么你需要的是 merge_pr。

恢复语义

使用 resume: true 调用时,处理程序会读取现有的 mergeOrchestrator 状态。终止阶段(completed / rolled-back / aborted,即 EXCLUDED_MERGE_PHASES 的成员)会提前结束,并返回记录的结果,不产生新事件,也不会调用执行器。非终止阶段(pending / executing)会继续执行全新的预检和执行器运行;这是安全的,因为底层 Git 操作对于已合并的分支具有幂等性。

不使用 resume 调用时,会有意忽略先前状态,即采用全新分发语义。

注意:target-checked-out-elsewhere 提前中止路径在读取恢复状态之前运行,因此无论 resume 为何值,都会提前结束,且不会持久化状态。

试运行

dryRun: true 会运行正文预检,发出 merge.preflight,并在执行器运行及任何状态持久化之前提前结束。返回 { dryRun: true, preflight, phase: 'pending' | 'aborted' }。适用于在合并窗口开启前检查合并就绪情况的 CI 集成。试运行仍会检查工作树是否可用——即使设置了 dryRun,同级工作树冲突也会以 reason: 'target-checked-out-elsewhere' 中止。

反模式

不要应改为
将原始 merge_orchestrate 分发到共享集成分支通过 serialize_merge 路由(单写入者租约);原始 merge_orchestrate 用于非集成合并或持有租约的合并——存在有效的其他租约时会失败关闭(MERGE_LEASE_HELD)
使用此技能合并远程 PR使用 merge_pr 技能
在正常流程中手动发出 merge.preflight / merge.requested / merge.executed / merge.recovered让处理程序自动发出;手动发出会导致重复(一个例外:recovery-runbook.md 中记载的手动恢复流程)
将合并事件包装在 gate.executed 下直接追加到流中,并使用专用事件类型——这些是状态转换,而不是门控执行
在 rolled-back 结果后不检查原因就重新分发读取 data.reason 和 data.recoveryErrorDetail(以及 data.recoveryError 判别字段);先解决根本原因
在 reason: 'target-checked-out-elsewhere' 后不先释放同级工作树就重新分发移除或重新检出 data.siblingWorktreePath 引用的同级工作树,然后重新分发
省略 --strategy / strategy: 字段并期待使用默认值必须指定策略;明确提供 squash / merge / rebase
从子 Agent 工作树调用预检会拒绝执行(主工作树断言);请从主工作树调用

诊断

在调用 merge_orchestrate 前,在环境中设置 EXARCHOS_PREFLIGHT_DEBUG=1,即可在 merge.preflight 事件中附加结构化调试载荷。该载荷受两个条件限制,且必须同时满足:

  1. 编排器进程环境中存在 EXARCHOS_PREFLIGHT_DEBUG=1。
  2. 预检的祖先关系守卫未通过(即 ancestry.passed === false)。

即使设置了环境变量,通过的预检也不会携带调试载荷——仅在失败时启用是有意为之(考虑到事件存储的增长)。未来的 EXARCHOS_PREFLIGHT_DEBUG=2 通道可能会添加详细或通过预检的诊断信息;这不属于第 1 阶段的范围。

调试块包含九个字段:

字段来源用途
gitVersiongit --version区分不同 Git 版本中的行为。
repoRootgit rev-parse --show-toplevel区分符号链接路径、规范化路径与原始仓库路径。
worktreeListgit worktree list --porcelain展示可能影响引用解析的同级工作树拓扑结构。
refsHeadsSourcegit for-each-ref refs/heads/<source>源分支引用的 SHA 和打包状态。
refsHeadsTargetgit for-each-ref refs/heads/<target>目标分支引用的 SHA 和打包状态。
mergeBaseCommand构造所得辅助程序重新运行的确切 argv,包括 'git' 前缀,可供操作员直接复制粘贴。
mergeBaseExitCode重新运行 git merge-base --is-ancestor <target> <source>导致祖先关系检查失败的退出代码。
mergeBaseStdout同一调用捕获的标准输出。
mergeBaseStderr同一调用捕获的标准错误(在默认 Git 适配器下会并入标准输出)。

失败时关闭:调试辅助程序中的任何单次 Git 调用失败时,该字段会使用空字符串或默认值,不会抛出异常。调试信息的附加操作绝不能掩盖操作员正试图排查的底层预检失败。

报告工作流。 捕获到包含调试信息的事件后,将完整的 data.debug 块附加到新的 GitHub issue,并添加相关范围标签(例如 windows、merge-orchestrator、preflight)。第 2 阶段的根因分析至少需要一个包含此载荷的真实主机事件。

架构发现

如需了解参数架构,请调用 exarchos:exarchos_orchestrate({ action: "describe", actions: ["merge_orchestrate"] })。事件载荷的形状可通过 exarchos:exarchos_event({ action: "describe", eventTypes: ["merge.preflight", "merge.requested", "merge.executed", "merge.rollback", "merge.recovered"] }) 获取(merge.rollback 是旧版、读取时兼容的事件——为支持重放 DR-2 之前的日志而保留,不再发出)。

工作流状态中的 mergeOrchestrator.* 字段由此技能写入,mergeOrchestrator.phase 由门控读取;底层的 phase 工作流字段不可变,必须通过 transition 而非 update 修改。完整的不可变键列表和类型化的 RESERVED_FIELD 错误信封,请参阅 checkpoint 技能中的保留字段部分。

完成标准

  • 预检结果为 passed: true(或操作员已决定尽管存在有记录的预检缺口仍继续)
  • 编排器状态中的 mergeOrchestrator.phase === 'completed'
  • 流中存在 merge.executed 事件,其中记录了 mergeSha 和 rollbackSha(恢复点对应的旧版线缆字段,在 v2.11.x 弃用期内保留)
  • 目标分支的 HEAD 与记录的 mergeSha 相符

如果任何一项标准未满足,请先查阅 references/recovery-runbook.md,再重新派发。

评论

支持 Markdown