首页
/ 深入解读 VS Code 内置 merge 技能:让 Agent 安全地把会话分支合并回基准分支

深入解读 VS Code 内置 merge 技能:让 Agent 安全地把会话分支合并回基准分支

2026-09-07 15:09:16作者:邵娇湘

导读

在 VS Code 的 Agent 会话(Sessions / Agents Window)机制中,AI Agent 常常在独立的"主题分支(topic branch)"上完成一次会话的开发工作,最终需要把这些成果合并回代表项目主干状态的"基准分支(merge base branch)"。仓库内置的 merge 技能说明 就是为这一场景量身定制的可执行工作流:它定义了 Agent 从"检查并提交未暂存改动"、"跨工作树执行合并"到"冲突裁决与结果校验"的完整操作协议,同时以明确的红线条款约束 Agent 绝不擅自强推、跳过钩子或改写提交历史。读完本文,你将掌握这套内置于 VS Code 会话体系中的 merge 技能的设计意图、完整命令流程、冲突处理约定,以及如何在 Agent 提示词工程中复用它保证合并操作安全可控。

SKILL.md 是什么:会话体系中可执行的工作流

src/vs/sessions 这一实现了 Agents Window 的源码目录下,skills/*/SKILL.md 是一类非常特殊的文件。根据 vs/sessions 的 README 中的说明,这些 skills/*/SKILL.md 文件是"可执行的产品工作流(executable product workflows)",它们并不属于架构设计文档,而是被直接喂给会话 Agent、指导其完成某个具体任务的指令模板。

merge 技能就是这套工作流家族中的一员。当前仓库中与其并列的兄弟技能还包括:

  • commit/SKILL.md:把工作树改动以符合仓库惯例的提交信息提交;
  • sync/SKILL.md:让当前会话分支与上游分支同步或发布新分支;
  • create-pr/SKILL.md:为当前会话的改动创建 Pull Request;
  • 以及 code-reviewfix-ciupdate-prsync-upstreamtroubleshoot 等其它同名目录。

从文件结构看(skills 目录),每个工作流都以同名目录 + SKILL.md 的形式组织,目录名即技能名。merge 技能目录 merge/SKILL.md 的文件本体十分精炼,包含 YAML front-matter、一段行为覆盖注释、Guidelines(准则)与 Workflow(工作流)四大部分,下面逐一展开。

front-matter:技能的"可被调起"声明

与 VS Code 会话体系中的其它技能一致,merge 技能的文档开头是一段 YAML front-matter:

name: merge
description: Merge changes from the topic branch to the merge base branch. Use when the user wants to merge their session's work back to the base branch.
  • name: merge 声明技能标识,Agent 上下文中的斜杠命令(如 /commit/merge)通常即按此名称索引。
  • description 承担"何时调用本技能"的语义描述:当用户希望把会话的工作成果合并回基准分支时使用。它同时界定了本技能的操作对象——**topic branch(当前工作树中检出的主题分支)**与 merge base branch(主工作树中检出的基准分支)

行为覆盖注释:内置技能如何被个性化

文件第 5 行有一段对运维实践非常关键的注释:

Customize this skill and select save to override its behavior. Delete that copy to restore the built-in behavior.

其含义是:这份 SKILL.md 是"内置(built-in)"版本。用户可以在界面中把该技能另存为自定义副本以覆盖默认行为;删除自定义副本后,将恢复使用这份内置行为。这一"内置可覆盖、删除即还原"的机制与 AI_CUSTOMIZATIONS.md 中描述的 AI 定制化管理模型相互呼应——在该架构说明中,skills、instructions、prompts 等定制项可在 workspace、user、extension、built-in 等不同来源间发现与覆盖,而"过滤只影响呈现、不修改底层定制项"的管线原则同样适用于 merge 技能。

Guidelines:合并操作不可逾越的红线

技能开头先用四条加粗的准则(Guidelines)圈定 Agent 的安全边界,任何后续工作流步骤都不得突破:

  • 未经用户明确批准,绝不强推(force-push),明确点名 --force--force-with-lease 均在禁止之列;
  • 绝不跳过 pre-push 钩子,即不得使用 --no-verify
  • 未经用户询问,绝不改写或丢弃提交(rewrite or drop commits);
  • 对冲突如何解决没有把握时,询问用户

从源码结构看,这些红线并非 merge 独有。对比 commit/SKILL.md 中的"绝不 amend 既有提交"、"绝不未经批准 force-push / push"、"绝不跳过 pre-commit / 签名钩子",以及 sync/SKILL.md 中同样禁止 force-push、禁止 --no-verify、禁止擅自改写提交的条款,可以推断:"不擅自强推、不绕过钩子、不丢提交、存疑即询问"是这套会话工作流的通用安全宪法。它们共同保证 Agent 的 git 操作对用户完全透明、可中止、可回退。

工作流全景:从提交未暂存改动到干净地合并

merge 技能把整个合并任务拆为"提交现场 → 合并 → 解决冲突 → 校验"四个环节,全程通过 git -C <main-worktree-path> 把命令定向到主工作树,而 Agent 自身停留在当前(会话)工作树中,这正体现了会话机制的分支/工作树模型。

第 1 步:先提交当前工作树的未暂存改动

合并的前提是当前工作树"干净"。因此第一步先做检查:

git status --porcelain
  • 若输出为空,说明当前工作树干净,可直接进入合并;
  • 若存在未提交改动,则应先调用 /commit 技能(即 commit/SKILL.md 定义的工作流)将其提交,再继续合并。

这一"先提交、后合并"的顺序非常重要:话题分支上的工作成果只有先固化为提交,后续才能被合并、被 merge-base --is-ancestor 校验;同时避免把未完成的半成品带入合并结果。

第 2 步:把 topic 分支合并进主工作树的基准分支

合并动作指向的是主工作树中检出的基准分支,因此技能特意强调使用 git -C 而非切换目录——-C <path> 会让 git 把指定路径当作工作目录来执行命令,而 Agent 不需要离开当前工作树、也不改变会话上下文:

git -C <main-worktree-path> merge <topic-branch>

需要说明的是,<main-worktree-path><topic-branch> 是占位符:技能正文明确写道"追加到提示词中的上下文块(context block)包含源分支、目标分支以及主工作树路径",即这两个取值由会话环境在运行时注入 Agent 的 prompt 中,技能本身只定义抽象步骤。从整体设计推断,这一"分支隔离在不同工作树 + 上下文注入分支信息"的模型,正是为了让多个 Agent 会话可在互不干扰的工作树中并行开发,最终统一汇入基准分支。

第 3 步:冲突处理四部曲

若第 2 步的 merge 报告冲突,按以下顺序处理:

3.1. 列出冲突文件,利用 diff-filter=U(Unmerged)只筛选处于"未合并"状态的文件:

git -C <main-worktree-path> diff --name-only --diff-filter=U

3.2. 逐一读取冲突文件内容,以"保留双方意图(preserving the intent of both sides)"为原则手动解决冲突,并将已解决文件暂存:

git -C <main-worktree-path> add <resolved-file>

3.3. 存疑即问,可整体中止。当无法确定如何解决某个冲突时,必须向用户征询指引;若用户希望放弃本次合并,则执行:

git -C <main-worktree-path> merge --abort

merge --abort 会把仓库恢复到合并开始前的状态,是技能为"用户反悔/Agent 陷入僵局"预留的明确逃生通道。

3.4. 全部解决并暂存后,以默认信息提交合并--no-edit 表示直接采用 git 自动生成的合并提交信息而不打开编辑器——这是无交互 Agent 场景下的必要选项:

git -C <main-worktree-path> commit --no-edit

校验:合并真的完成了吗

合并提交完成后,不能直接宣告成功,必须执行两条显式校验:

  1. 确认主工作树干净
git -C <main-worktree-path> status --porcelain
  1. 确认 topic 分支已是基准分支 HEAD 的祖先——即 topic 上所有提交都确实进入了基准分支:
git -C <main-worktree-path> merge-base --is-ancestor <topic-branch> HEAD

其中第二条命令的语义值得展开:git merge-base --is-ancestor A B 在 A 是 B 的祖先时返回退出码 0(真),否则返回非 0。因此该命令相当于一条程序化的包含性断言——只有当返回值表明 <topic-branch> 的全部提交都已并入 HEAD(基准分支)时,合并才算真正闭环。这种"用 git 自身的图论关系做校验、而非仅凭肉眼看过文件"的验证手法,与 sync/SKILL.md 结尾用 git rev-list --left-right --count HEAD...@{u} 校验 ahead/behind 均为 0 的做法如出一辙,可以推断**"显式命令 + 退出码断言"是本套工作流标准的结果验证范式**。

与兄弟技能的协作关系:一条完整的分支生命周期

把 merge 技能放入它周围的技能网络中,可以还原出 Agent 处理一次会话改动的完整生命周期(均为仓库内真实存在的技能目录,可对照查看原文):

阶段 技能 对应 SKILL.md
收尾未提交改动 /commit commit/SKILL.md
与上游同步 / 发布分支 /sync sync/SKILL.md
将会话成果合并回基准分支 /merge(本文主题) merge/SKILL.md
把会话改动对外提交为 PR /create-pr create-pr/SKILL.md

值得注意的是,merge 技能第 1 步明确委托 /commit 技能,而 create-pr/SKILL.md 的第 2 步同样写着"若存在未提交改动,先用 /commit 技能提交"。这说明技能之间以明确的委托关系互相组合:commit 是一切下游 git 操作的公共前置依赖。merge 则承接 commit 之后、create-pr 发布之前的"并入主干"环节——当用户希望把会话成果合并回基准分支时触发;若用户希望以 PR 形式把改动对外发布,则由 create-pr 接手。这份依赖设计使每个技能保持单薄、聚焦、可独立验证,符合 vs/sessions README 对"可执行产品工作流"的定位。

实际使用中的适用前提与限制

综合技能正文与仓库证据,使用 merge 技能需要注意以下前提,它们也是该技能适用边界的事实说明:

  • 面向双工作树/多分支模型:技能假设当前(会话)工作树检出了 topic branch、主工作树检出了 merge base branch。如果仓库实际并未使用 git worktree 拆分的多工作树布局,则 <main-worktree-path> 与当前路径指向同一仓库,命令仍然成立,但"隔离合并现场"的设计收益会减弱。
  • 依赖运行时注入上下文:源分支、目标分支、主工作树路径均来自追加进 prompt 的 context block,而非技能文件内置。也就是说,技能只规定"做什么与按什么顺序做",实际参数由会话运行时提供。
  • 冲突解决依赖 Agent 判断力:"保留双方意图"是原则而非算法,最终是否冲突收敛依赖 Agent 对代码上下文的理解;技能为不确定场景预留的标准动作是询问用户或 merge --abort 整体放弃。
  • 红线不可突破:即便某个环节看似需要强推或绕过钩子才能推进,Guidelines 也已预先封死这些选项——唯一的合法出口是向用户申请明确批准。

若内置行为不完全符合你的团队约定(例如希望默认采用 --no-ff 合并或更严格的校验),可按照该文件开头的注释说明,将技能另存为自定义副本后按需改写;删除自定义副本即可恢复本仓库这份内置的默认行为。

登录后查看全文
热门项目推荐
相关项目推荐