VS Code Sessions 内置 Skill 解析:sync-upstream 如何让落后的会话分支安全跟上最新上游
本篇指南围绕 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/ 目录下与 commit、merge、create-pr、update-pr、fix-ci 等并列打包的内置技能。
二、完整工作流:先提交、再 fetch、再 rebase
Skill 正文给出的标准工作流只有两步,但第二步隐含了"基线分支不一定叫 main"的适配要求:
1. 处理未提交变更
If there are uncommitted changes, use the
/commitskill 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(例如 master、dev),需要把 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 完成后做两层验证:
- 可编译性:验证结果仍然能编译通过(verify the result still compiles);
- 目标达成性:验证是否仍满足会话的既定目标(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()):
- 通过 fileService 解析
vs/sessions/skills根目录,遍历其下每个子目录; - 在每个子目录中定位
SKILL.md(文件名常量定义于 promptFileLocations.ts,匹配大小写不敏感),调用parseNew()解析 frontmatter; - frontmatter 中
name与description缺一不可,否则该技能被静默跳过——这正解释了 sync-upstream 的 SKILL.md 头部两个字段为何是"必填项"; - 再做两处一致性校验:
name经sanitizeSkillText处理(去 XML 标签、截断至 64 字符)后必须与所在文件夹名一致,不一致直接丢弃。所以目录必须叫sync-upstream、frontmatter 的name必须写sync-upstream,这也是技能名只能是小写字母、数字和连字符(VALID_SKILL_NAME_REGEX = /^[a-z0-9-]+$/)的原因; - 解析失败只记录 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 定义的工作流本身就是一套可移植的"落后分支追赶"清单:
- 工作区不干净先提交(复用既有的提交规范);
git fetch origin+git rebase origin/<base>(base 不一定是 main);- 冲突时上游逻辑无条件保留,会话侧工作重命名/重构/重写去适配,逐个
git add+git rebase --continue; - rebase 结束后验证编译与目标达成,若会话工作已失去意义,说明变化并给出修订方案。
配合 commit 技能对提交动作的约束(不改历史、不跳钩子)与 sync 技能对 tracking 分支日常同步的约束,这三个内置技能共同覆盖了会话分支"提交 → 日常同步 → 大跨度追赶"的完整生命周期,而 AgenticPromptsService 的加载与优先级机制则保证了团队或个人可以按 .agents/skills 等约定位置定制自己的版本,随时回退到内置默认。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00