首页
/ VS Code Sessions 内置 Skill 解析:sync-upstream 如何让落后的会话分支安全跟上最新上游

VS Code Sessions 内置 Skill 解析:sync-upstream 如何让落后的会话分支安全跟上最新上游

2026-09-07 14:37:10作者:龚格成

本篇指南围绕 VS Code 仓库中打包的内置 Skill 文件 sync-upstream/SKILL.md 展开,讲清楚这个"分支更新"技能定义了怎样的 Git 工作流程、冲突裁决原则与验证标准,并结合会话端 Skill 发现机制的源码说明它如何被加载、如何被用户定制覆盖。读完后你能掌握:在会话分支落后上游较多时如何 rebase 跟上、冲突时"上游永远优先"策略的落地方式,以及该 Skill 在 VS Code 中的解析与优先级机制。

一、这个 Skill 解决什么问题

SKILL.md 的 frontmatter 明确界定了它的触发场景:

name: sync-upstream
description: Update a stale session branch by rebasing onto the latest origin.
  Use when the upstream has moved significantly and the session needs to catch up,
  resolving conflicts by preserving upstream changes and adapting session work to fit.

也就是说,当会话(session)分支基于某个上游基线(如 origin/main)开展工作后,上游已经前进了很多提交,本地会话分支"明显落后"时,就需要用该技能把会话分支 rebase 到最新上游,让会话中的工作继续"立足于"当前主干之上。

这里值得区分一下它和相邻的 /sync 技能

  • sync:面向"当前分支与其 tracking 上游分支(@{u})之间的同步",用 git rev-list --left-right --count HEAD...@{u} 检查 ahead/behind,落后则 git rebase @{u},并把本地提交 push 出去;没有上游时则 git push -u <remote> HEAD 发布分支。
  • sync-upstream:面向"分支落后于上游基线分支较多"的追赶场景,目标是把整个会话分支 rebase 到 origin/<base> 上,冲突裁决规则更激进——上游无条件胜出。

两者都是 src/vs/sessions/skills/ 目录下与 commitmergecreate-prupdate-prfix-ci 等并列打包的内置技能。

二、完整工作流:先提交、再 fetch、再 rebase

Skill 正文给出的标准工作流只有两步,但第二步隐含了"基线分支不一定叫 main"的适配要求:

1. 处理未提交变更

If there are uncommitted changes, use the /commit skill to commit them first.

rebase 要求工作区干净。该技能要求直接复用内置的 /commit 技能 先完成提交,而不是让用户手工操作。这个 commit 技能自身的规范(采样 git log --oneline -20 推断提交信息风格、区分 staged/unstaged、禁止 --no-verify--no-gpg-sign 等)也构成了 rebase 前置步骤的行为约束。

2. 抓取最新上游并 rebase

git fetch origin
git rebase origin/main

并附带一条重要的适配说明:"Use the appropriate base branch if it is not main." —— 如果仓库的默认基线分支不是 main(例如 masterdev),需要把 rebase 的目标换成对应的 origin/<base-branch>

sync 技能不同,这里没有"ahead/behind 为 0 就停止"的短路判断,也没有 rebase 后 push 的步骤——因为它的语义是"追赶基线",是否推送、如何推送(rebase 改写了历史,通常需要 --force-with-lease)由后续的用户操作决定,技能本身刻意不扩大权限边界。

三、冲突裁决策略:上游永远胜出

这是该 Skill 最具特色、也最容易和常规 rebase 习惯拉开差距的部分。文档原文规定,当 rebase 产生冲突时 upstream always wins

  • Never alter upstream logic, APIs, or patterns to accommodate session changes. —— 为了迁就会话改动,永远不去改上游的逻辑、API 或代码模式;
  • Adapt session work to fit the new upstream —— 相反,去改造会话侧的工作来适配新上游:按需重命名、重构甚至重写,但要保持会话本身的目标(session's goals)不变;
  • 每解决一个冲突后,git add 相关文件并 git rebase --continue 继续。

从实践角度看,这条规则的本质是:会话分支的定位是"在最新上游之上的增量工作",上游的演进代表项目的主方向,会话侧的旧实现天然应让位。它避免了 rebase 冲突中常见的"两边各改一半、语义拧巴"的结果,保证 rebase 完成后代码在语义上等同于"新上游 + 以新上游为前提重做的会话工作"。

四、验证:rebase 完成不等于任务完成

Skill 的 Validation 部分要求 rebase 完成后做两层验证:

  1. 可编译性:验证结果仍然能编译通过(verify the result still compiles);
  2. 目标达成性:验证是否仍满足会话的既定目标(meets the session's objectives)。

并且给出了一条兜底原则:如果会话的改动在更新后的上游之上已经不再有意义,应当解释清楚上游发生了什么变化,并主动提出修订后的方案(propose a revised approach),而不是硬塞一个失去意义的补丁集。

五、源码视角:这个 Skill 如何被 VS Code 发现与加载

这个 SKILL.md 并不只是一份"人读的说明",它会被 VS Code 的会话端 Skill 发现机制解析为可被模型调用的技能。核心实现见 AgenticPromptsService

/** URI root for built-in skills bundled with the Agents app. */
export const BUILTIN_SKILLS_URI = FileAccess.asFileUri('vs/sessions/skills');

内置技能的发现流程(discoverBuiltinSkills()):

  1. 通过 fileService 解析 vs/sessions/skills 根目录,遍历其下每个子目录;
  2. 在每个子目录中定位 SKILL.md(文件名常量定义于 promptFileLocations.ts,匹配大小写不敏感),调用 parseNew() 解析 frontmatter;
  3. frontmatter 中 namedescription 缺一不可,否则该技能被静默跳过——这正解释了 sync-upstream 的 SKILL.md 头部两个字段为何是"必填项";
  4. 再做两处一致性校验:namesanitizeSkillText 处理(去 XML 标签、截断至 64 字符)后必须与所在文件夹名一致,不一致直接丢弃。所以目录必须叫 sync-upstream、frontmatter 的 name 必须写 sync-upstream,这也是技能名只能是小写字母、数字和连字符(VALID_SKILL_NAME_REGEX = /^[a-z0-9-]+$/)的原因;
  5. 解析失败只记录 warn 日志,不影响其他技能加载。

优先级与"定制覆盖"机制

每个内置 SKILL.md 正文里都有同一行 HTML 注释:

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

这行提示与源码中的优先级策略严格对应。AgenticPromptsService 的注释明确写道:"Built-ins have the lowest skill priority, so a user/workspace skill with the same folder name wins." —— 内置技能优先级最低,只要用户或工作区提供了同名的技能文件夹,内置版本就被覆盖。

而用户/工作区技能的可放置位置由 DEFAULT_SKILL_SOURCE_FOLDERS 定义:

路径 作用域 存储类型
.agents/skills 工作区 local
.github/skills 工作区 local
.claude/skills 工作区 local
~/.agents/skills 用户主目录 user
~/.copilot/skills 用户主目录 user
~/.claude/skills 用户主目录 user

因此,文档中"复制该技能、修改后保存即可覆盖内置行为;删除副本即恢复内置行为"的说法,正是"同名覆盖 + 内置兜底"这一优先级模型在用户侧的直接映射。

六、小结:可复制的分支追赶模式

即便脱离 VS Code 的技能机制,sync-upstream 定义的工作流本身就是一套可移植的"落后分支追赶"清单:

  1. 工作区不干净先提交(复用既有的提交规范);
  2. git fetch origin + git rebase origin/<base>(base 不一定是 main);
  3. 冲突时上游逻辑无条件保留,会话侧工作重命名/重构/重写去适配,逐个 git add + git rebase --continue
  4. rebase 结束后验证编译与目标达成,若会话工作已失去意义,说明变化并给出修订方案。

配合 commit 技能对提交动作的约束(不改历史、不跳钩子)与 sync 技能对 tracking 分支日常同步的约束,这三个内置技能共同覆盖了会话分支"提交 → 日常同步 → 大跨度追赶"的完整生命周期,而 AgenticPromptsService 的加载与优先级机制则保证了团队或个人可以按 .agents/skills 等约定位置定制自己的版本,随时回退到内置默认。

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