Superpowers 实战:用 finishing-a-development-branch 技能规范开发分支的合并、PR 与工作区清理
本篇技术文章以 Superpowers 框架中的 finishing-a-development-branch 技能文档为主体,完整讲解它在"实现完成、测试通过"这一节点上的标准收尾流程:先验证测试、再检测 git 环境、然后向人类伙伴呈现集成选项、执行选择,最后按"来源归属"原则清理 worktree。读完后你将掌握一套可在任意 Agent 协作开发场景中复用的分支收尾方法论,包括环境检测命令、合并/PR/保留/丢弃四种路径的具体命令序列,以及防止误清理工作区的回归测试验证方式。
技能定位:开发流程的最后一环
在 Superpowers 的技能体系中,finishing-a-development-branch 专门处理"实现已完成、所有测试通过、需要决定如何集成这些工作"的场景(见 SKILL.md 的 frontmatter 描述)。它的核心原则被概括为一句话:
Verify tests → Detect environment → Present options → Execute choice → Clean up. (验证测试 → 检测环境 → 呈现选项 → 执行选择 → 清理)
并且要求在启动时明确宣告:"I'm using the finishing-a-development-branch skill to complete this work."(我正在使用 finishing-a-development-branch 技能完成这项工作)。
从源码结构看,它是整个开发流程图的终点节点:
- executing-plans 的 Step 3(Complete Development)规定:所有任务完成并验证后,必须宣告并使用
superpowers:finishing-a-development-branch,按其流程验证测试、呈现选项、执行选择; - subagent-driven-development 的 Finish 阶段在最终整分支评审(Final Review)通过后,先删除该计划的工作区目录(
rm -rf <workspace>,git 历史此时已是唯一记录),随后同样进入Use superpowers:finishing-a-development-branch; - README.md 也将它列为标准流程之一:"Activates when tasks complete. Verifies tests, presents options (merge/PR/keep/discard), cleans up worktree."
也就是说,本技能既是"计划执行"和"子代理驱动开发"两条路径的公共收尾出口,也是集成决策权从 Agent 交还给人类伙伴的正式节点。
Step 1: Verify Tests(验证测试)
第一步是运行项目的完整测试套件(npm test / cargo test / pytest / go test ./...),且规则是刚性的:测试失败则报告失败项并停止——选项菜单(menu)只出现在绿色套件之后。文档中给出的报告格式为:
Tests failing (<N> failures). Must fix before completing:
[Show failures]
测试通过才继续进入 Step 2。
这一条对应技能末尾"Common Rationalizations"表中最重要的反驳之一:"Tests passed earlier this session"(本会话早些时候测试是过的)——现实是:必须在你即将集成的这棵树上运行套件。一次绿色运行只能证明它当时运行的那棵树,不能证明合并后的结果。
Step 2: Detect Environment(检测环境)
进入收尾阶段后,先用三条只读 git 命令确定自己处于什么工作区形态:
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
# Capture now, while still inside the workspace — Step 5 changes directory
# before cleanup (Step 6) needs this value
WORKTREE_PATH=$(git rev-parse --show-toplevel)
注意注释中的关键细节:WORKTREE_PATH 必须在进入工作区时立刻捕获,因为 Step 5(执行选择)会先改变目录,而 Step 6(清理)要用这个值——不能事后重查。
三个值的组合决定了菜单形态和清理方式:
| 状态 | 菜单 | 清理方式 |
|---|---|---|
GIT_DIR == GIT_COMMON(普通仓库) |
标准 3 选项 | 没有 worktree 需要清理 |
GIT_DIR != GIT_COMMON,命名分支 |
标准 3 选项 | 按来源归属处理(见 Step 6) |
GIT_DIR != GIT_COMMON,detached HEAD |
精简 2 选项(无 merge) | 外部托管——原地保留 |
这套"用 git 原语检测状态、而不是嗅探平台环境变量"的设计来自 Superpowers 的 worktree 重构(rototill)设计文档 2026-04-06-worktree-rototill-design.md。该文档明确了设计原则 Detect state, not platform:用 GIT_DIR != GIT_COMMON 判断"我是否已在 worktree 中",而非检测环境变量识别是哪个 harness——这是 git 2.5(2015 年)起就稳定的原语,跨平台通用,且新 harness 出现时无需维护。设计文档同时解释了为什么 detached HEAD 状态必须去掉 merge 选项:无法从 detached HEAD 发起合并。
using-git-worktrees 的 Step 0 还补充了一个收尾场景同样值得注意的防护——submodule guard:GIT_DIR != GIT_COMMON 在 git 子模块内部也为真,所以判断"是否 worktree"前应先执行 git rev-parse --show-superproject-working-tree,有返回路径说明你在子模块而非 worktree,应当作普通仓库处理。codex-tools.md 的平台参考也复用同一组检测命令,并说明 Codex App 沙箱(detached HEAD、外部托管 worktree)下 Agent 应改为提交全部工作后引导用户走 App 的原生"Create branch"/"Hand off to local"控件。
Step 3: Determine Base Branch(确定基础分支)
基础分支就是本次工作所分叉的那个分支——通常已在计划文档、对话上下文或分支的 upstream 中被指明。如果尚不清楚,就问:"This branch split from — is that correct?"(这个分支是从 <你的最佳猜测> 分出来的——对吗?)
文档强调合并前必须确认:合错基础分支的代价是"昂贵到难以撤销"(merging into the wrong base is expensive to undo)。这一条同样出现在 Rationalizations 表里,专门反驳 "The base branch is obviously main"(基础分支显然是 main)这种偷懒推断。
Step 4: Present Options(呈现选项)
菜单必须逐字照写("Present the menu exactly as written"),每个选项都来自文档给出的固定列表;Agent 不得自行增删——尤其是不得主动提供"丢弃"选项(见下节专项说明)。
普通仓库与命名分支 worktree —— 恰好呈现这 3 个选项:
Implementation complete. What would you like to do?
1. Merge back to <base-branch> locally
2. Push and create a Pull Request
3. Keep the branch as-is (I'll handle it later)
Which option?
Detached HEAD —— 恰好呈现这 2 个选项:
Implementation complete. You're on a detached HEAD (externally managed workspace).
1. Push as new branch and create a Pull Request
2. Keep as-is (I'll handle it later)
Which option?
呈现后等待人类回答——集成决策权属于人类伙伴。文档的原文表述是:"Discarding the work happens only in response to your human partner explicitly asking for it."(丢弃工作只会发生在人类伙伴明确提出要求时。)
Step 5: Execute Choice(执行选择)
Option 1: Merge Locally(本地合并)
# Get main repo root for CWD safety
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
# Merge first — verify success before removing anything
git checkout <base-branch>
git pull
git merge <feature-branch>
# Verify tests on merged result
<test command>
两个要点值得注意:
- CWD 安全:先通过
git-common-dir反推出主仓库根目录再cd,因为合并操作必须发生在主仓库而非 worktree 内; - 顺序保证:先合并、验证成功,之后才允许删除任何东西("Merge first — verify success before removing anything")。
合并结果测试失败时:停止,保留 worktree 和分支原样,展开调查——此时还没有任何 push,合并是纯本地的、可恢复的。
合并结果变绿后:先执行 Step 6 清理 worktree,再删除分支:
git branch -d <feature-branch>
Option 2: Push and Create PR(推送并创建 PR)
git push -u origin <feature-branch>
# From a detached HEAD, name the new branch on the remote:
# git push origin HEAD:refs/heads/<new-branch>
随后用托管平台(forge)的工具对 <base-branch> 创建 PR/MR——有 CLI 用 CLI,没有就用多数 forge 在 push 时打印的创建 URL——若仓库存在 PR 模板与约定则遵循,并把 URL 报告给人类伙伴。
保留 worktree——人类伙伴会在该 worktree 里迭代处理 PR 评审反馈。Rationalizations 表专门反驳了 "The PR is up, so the worktree is clutter now"(PR 已经开了,worktree 现在是杂物)这种直觉:"PR feedback gets fixed in that worktree. It stays until the work lands."(PR 反馈就在那个 worktree 里修。它留到工作落地为止。)
Option 3: Keep As-Is(保持原样)
报告一句即可:"Keeping branch . Worktree preserved at
If your human partner asks to discard the work(仅当人类明确要求丢弃)
丢弃路径只作为对明确丢弃请求的响应而存在,且必须先确认——把将永久删除的内容逐项列出:
This will permanently delete:
- Branch <name>
- All commits: <commit-list>
- Worktree at <path>
Type 'discard' to confirm.
等待精确的确认词。文档规定:只有输入的单词 discard 才授权删除——"Yeah, get rid of it" 这类口语化同意不算数。确认到达后:
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
然后执行 Step 6 清理 worktree,并强制删除分支:
git branch -D <feature-branch>
注意这里用 git branch -D(强删),区别于 Option 1 中合并完成后的安全删除 git branch -d。
Step 6: Cleanup Workspace(清理工作区)
本步只在 Option 1 和已确认的丢弃时运行;Option 2 和 Option 3 永远保留 worktree。两个调用方此时都已 cd 到主仓库根——worktree 移除必须从 worktree 外部执行——并且使用的是 Step 2 中捕获的 GIT_DIR/GIT_COMMON/WORKTREE_PATH 值(在目录改变之前捕获的)。
分三种情况:
情况一:GIT_DIR == GIT_COMMON。 普通仓库,没有 worktree 需要清理,结束。
情况二:WORKTREE_PATH 位于 .worktrees/ 或 worktrees/ 之下。 Superpowers 自己创建了该 worktree,因此拥有清理权:
git worktree remove "$WORKTREE_PATH"
git worktree prune # Self-healing: clean up any stale registrations
情况三:其他位置。 宿主环境拥有该工作区——原地保留。若平台提供退出工作区的工具,则使用它。
这里的判定标准就是 rototill 设计文档中的 Provenance-based ownership(来源归属所有权)原则:"Whoever creates the worktree owns its cleanup."(谁创建 worktree,谁负责清理。)Superpowers 创建的(落在 .worktrees/ 或 worktrees/ 下)由 Superpowers 清理;harness 创建的(如 .claude/worktrees/、~/.codex/worktrees/、.gemini/worktrees/)或旧的用户全局路径则一律不碰。
这条所有权边界还有一条可执行的回归测试保障:tests/claude-code/test-worktree-path-policy.sh 会断言 finishing-a-development-branch 技能文件(1)不再提及旧的全局路径 ~/.config/superpowers/worktrees,(2)仍然保留 ".worktrees/ or worktrees/" 的项目本地清理所有权表述,确保重构演进中不会把别人的工作区误删。
Quick Reference(速查表)
| 选项 | 合并 | 推送 | 保留 Worktree | 清理分支 |
|---|---|---|---|---|
| 1. 本地合并 | yes | - | - | yes |
| 2. 创建 PR | - | yes | yes | - |
| 3. 保持原样 | - | - | yes | - |
| 丢弃(仅限明确要求) | - | - | - | yes(强删) |
Common Rationalizations:九种典型越界冲动与纠正
技能文档最有方法论价值的部分,是它预先列举了 Agent 在收尾阶段的九种"合理化借口",并逐条给出事实性纠正。完整继承如下:
| 借口 | 现实 |
|---|---|
| "Tests passed earlier this session"(本会话早些时候测试通过过) | 在你即将集成的树上运行套件。绿色运行只证明它当时运行过的那棵树。 |
| "They obviously want it merged"(他们显然想合并) | 集成是人类伙伴的决定。呈现菜单并等待。 |
| "They seem done with this feature — I'll offer to discard it"(他们好像用完这个功能了——我主动提议丢弃吧) | 菜单按原文就是完整的。丢弃只发生在人类伙伴原话提出时。 |
| "'Yeah, get rid of it' counts as confirmation"("是啊,扔了吧"也算确认) | 只有输入的单词 discard 授权删除。 |
| "The PR is up, so the worktree is clutter now"(PR 开了,worktree 就是杂物了) | PR 反馈就在那个工作区里修。它留到工作落地。 |
| "This other worktree looks stale — I'll clean it too"(另一个 worktree 看起来过期了——顺手清掉) | 只清理 .worktrees/ 或 worktrees/ 下的 worktree。其余的属于宿主。 |
| "The merged-result failure is probably flaky"(合并结果失败大概是偶发抖动) | 合并结果失败就停止一切。分支和 worktree 保持原样直到调查清楚。 |
| "The base branch is obviously main"(基础分支显然是 main) | 确认分叉点,或开口问。合错基础分支难以撤销。 |
| "The push was rejected — force-push will fix it"(push 被拒——force-push 能修好) | push 被拒意味着远端移动了。先调查;force-push 只在人类伙伴明确要求时进行。 |
这张表本质上是把"权限边界"写成了可检查的行为规则:测试门禁、决策权归属、确认词字面匹配、清理所有权范围——每一条都可以被测试或评审直接核验。
适用前提与延伸阅读
需要说明的前提:本文所述流程绑定 Superpowers 的技能文档(Markdown 指令文件),它约束的是运行在 Claude Code、Codex、Gemini CLI 等 harness 中的 Agent,而非直接运行给人类的脚本;<base-branch>、<feature-branch>、<test command> 等占位符需在具体项目中替换。工作区创建侧的完整规则(同意询问、原生工具优先、git check-ignore 安全检查等)见 skills/using-git-worktrees/SKILL.md;环境检测与 Codex App 沙箱收尾见 skills/using-superpowers/references/codex-tools.md;设计动机与决策记录见 docs/superpowers/specs/2026-04-06-worktree-rototill-design.md 与 docs/superpowers/plans/2026-04-06-worktree-rototill.md,行为回归测试见 tests/claude-code/test-worktree-path-policy.sh。
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 StartedRust0622
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