From 9fcce2666276c577537d6742841519146a33b0a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI=E4=B8=8D=E6=AD=A2=E8=AF=AD?= <12096460+jnMetaCode@users.noreply.github.com> Date: Tue, 12 May 2026 00:36:51 +0800 Subject: [PATCH] =?UTF-8?q?chore(skills):=20=E5=90=8C=E6=AD=A5=E4=B8=8A?= =?UTF-8?q?=E6=B8=B8=20v5.1.0=20worktree=20=E5=AE=89=E5=85=A8=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=88issue=20#19=20=E7=AC=AC=E4=B8=80=E6=89=B9?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 把 upstream/main v5.1.0 在 using-git-worktrees + finishing-a-development-branch 两个 skill 上的行为变更逐字翻译同步过来。属于上游修复 obra/superpowers#991 (subagent 自动创建嵌套 worktree、清理误删 harness-managed workspace)。 using-git-worktrees: - 新增 Step 0:GIT_DIR vs GIT_COMMON 检测现有隔离,submodule 守卫 - 新增创建前同意流程(除非 instructions 已声明偏好) - 重组 Step 1 为 1a Native Tools (首选) + 1b Git Worktree Fallback - 新增沙盒回退(permission error 时原地工作) - 删除旧"示例工作流"段(含 /Users/jesse 硬编码路径) - 保留章节编号 Step 1→3 的上游怪癖(不擅自"修正") finishing-a-development-branch: - 新增 Step 2 检测环境(三态表决定菜单形态和清理逻辑) - 旧 Step 2/3/4/5 重编号为 3/4/5/6 - Step 4 新增分离 HEAD 3 选项变体 - Step 5 Option 1 重写:MAIN_ROOT cwd safety + merge→verify→cleanup→delete 严格排序 - Step 5 Option 2 增加 "Do NOT cleanup worktree" 提示(PR 迭代需要) - Step 6 清理范围限定:只清 .worktrees/ / worktrees/ / ~/.config/superpowers/worktrees/ 之内的;外部 harness-managed workspace 一律不动(核心安全修复) - 红线 + 常见错误段扩展(按上游对应同步) 翻译原则: - 章节标题翻译,但保留章节编号 (Step 0/1/3/4 一一对应) - 代码块完全保留,不翻译变量名/命令 - 散文逐句翻译,不简化不扩写 - 我们独有的 "## 集成" 段保留(指向 brainstorming/subagent-driven-development 等) 不属于本 PR 范围: - review loop 简化(v5.0.6 brainstorming/writing-plans)→ 下一批 - code-reviewer 整合(v5.1.0 requesting-code-review)→ 下一批 - subagent 节奏调整 (v5.1.0 subagent-driven-development) → 下一批 - brainstorm server.cjs 脚本结构同步 (v5.0.6 CONTENT_DIR/STATE_DIR) → 单独 PR Refs: jnMetaCode/superpowers-zh#19 --- .../finishing-a-development-branch/SKILL.md | 139 +++++++++--- skills/using-git-worktrees/SKILL.md | 211 ++++++++++-------- 2 files changed, 221 insertions(+), 129 deletions(-) diff --git a/skills/finishing-a-development-branch/SKILL.md b/skills/finishing-a-development-branch/SKILL.md index c9a2b53..55e7bd8 100644 --- a/skills/finishing-a-development-branch/SKILL.md +++ b/skills/finishing-a-development-branch/SKILL.md @@ -9,7 +9,7 @@ description: 当实现完成、所有测试通过、需要决定如何集成工 通过提供清晰的选项并执行所选工作流来引导开发工作的收尾。 -**核心原则:** 验证测试 → 展示选项 → 执行选择 → 清理。 +**核心原则:** 验证测试 → 检测环境 → 展示选项 → 执行选择 → 清理。 **开始时宣布:** "我正在使用 finishing-a-development-branch 技能来完成这项工作。" @@ -25,6 +25,7 @@ npm test / cargo test / pytest / go test ./... ``` **如果测试失败:** + ``` 测试失败( 个失败)。必须先修复才能继续: @@ -37,7 +38,24 @@ npm test / cargo test / pytest / go test ./... **如果测试通过:** 继续步骤 2。 -### 步骤 2:确定基础分支 +### 步骤 2:检测环境 + +**在展示选项之前,先确定工作区状态:** + +```bash +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) +``` + +这决定了展示哪种菜单、以及清理方式: + +| 状态 | 菜单 | 清理 | +|------|------|------| +| `GIT_DIR == GIT_COMMON`(普通仓库) | 标准 4 个选项 | 无 worktree 可清理 | +| `GIT_DIR != GIT_COMMON`,命名分支 | 标准 4 个选项 | 按来源判断(见步骤 6) | +| `GIT_DIR != GIT_COMMON`,分离 HEAD | 收敛 3 个选项(无合并) | 无清理(由外部管理) | + +### 步骤 3:确定基础分支 ```bash # 尝试常见的基础分支 @@ -46,9 +64,9 @@ git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null 或者询问:"这个分支是从 main 分出来的——对吗?" -### 步骤 3:展示选项 +### 步骤 4:展示选项 -展示以下 4 个选项: +**普通仓库和命名分支 worktree —— 准确展示以下 4 个选项:** ``` 实现已完成。你想怎么做? @@ -61,30 +79,45 @@ git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null 选哪个? ``` -**不要添加解释** - 保持选项简洁。 +**分离 HEAD —— 准确展示以下 3 个选项:** + +``` +实现已完成。你在分离 HEAD 上(由外部管理的工作区)。 + +1. 作为新分支推送并创建 Pull Request +2. 保持现状(我稍后处理) +3. 丢弃这项工作 + +选哪个? +``` + +**不要添加解释** —— 保持选项简洁。 -### 步骤 4:执行选择 +### 步骤 5:执行选择 #### 选项 1:本地合并 ```bash -# 切换到基础分支 -git checkout +# 切到主仓库根目录,保证 CWD 安全 +MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel) +cd "$MAIN_ROOT" -# 拉取最新代码 +# 先合并 —— 在删除任何东西之前先验证合并成功 +git checkout git pull - -# 合并功能分支 git merge # 在合并结果上验证测试 -# 如果测试通过 -git branch -d +# 合并成功之后再:清理 worktree(步骤 6),然后删除分支 ``` -然后:清理工作树(步骤 5) +然后:清理 worktree(步骤 6),再删除分支: + +```bash +git branch -d +``` #### 选项 2:推送并创建 PR @@ -103,7 +136,7 @@ EOF )" ``` -然后:清理工作树(步骤 5) +**不要清理 worktree** —— 用户在 PR 反馈迭代时还需要它存活。 #### 选项 3:保持现状 @@ -114,6 +147,7 @@ EOF #### 选项 4:丢弃 **先确认:** + ``` 这将永久删除: - 分支 @@ -126,28 +160,40 @@ EOF 等待精确的确认。 确认后: + ```bash -git checkout -git branch -D +MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel) +cd "$MAIN_ROOT" ``` -然后:清理工作树(步骤 5) +然后:清理 worktree(步骤 6),再强制删除分支: + +```bash +git branch -D +``` -### 步骤 5:清理工作树 +### 步骤 6:清理工作区 -**对于选项 1、2、4:** +**只对选项 1 和 4 执行。** 选项 2 和 3 始终保留 worktree。 -检查是否在工作树中: ```bash -git worktree list | grep $(git branch --show-current) +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) +WORKTREE_PATH=$(git rev-parse --show-toplevel) ``` -如果是: +**如果 `GIT_DIR == GIT_COMMON`:** 普通仓库,无 worktree 可清理。结束。 + +**如果 worktree 路径在 `.worktrees/`、`worktrees/` 或 `~/.config/superpowers/worktrees/` 之下:** 这是 Superpowers 创建的 worktree —— 我们负责清理。 + ```bash -git worktree remove +MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel) +cd "$MAIN_ROOT" +git worktree remove "$WORKTREE_PATH" +git worktree prune # 自愈:清理任何过期的注册记录 ``` -**对于选项 3:** 保留工作树。 +**否则:** 这个工作区由宿主环境(harness)管理。**不要**移除它。如果你的平台提供了工作区退出工具,用它。否则原样保留工作区。 ## 快速参考 @@ -161,40 +207,69 @@ git worktree remove ## 常见错误 **跳过测试验证** + - **问题:** 合并损坏的代码、创建失败的 PR - **修复:** 在提供选项前始终验证测试 **开放式问题** + - **问题:** "接下来该做什么?" → 含糊不清 -- **修复:** 准确展示 4 个结构化选项 +- **修复:** 准确展示 4 个结构化选项(分离 HEAD 时是 3 个) + +**为选项 2 清理 worktree** -**自动清理工作树** -- **问题:** 在可能还需要工作树时就删除了(选项 2、3) +- **问题:** 删掉用户 PR 迭代还需要的 worktree - **修复:** 只在选项 1 和 4 时清理 +**先删分支再删 worktree** + +- **问题:** `git branch -d` 失败,因为 worktree 还引用着该分支 +- **修复:** 先合并,再删 worktree,最后删分支 + +**在 worktree 内部跑 `git worktree remove`** + +- **问题:** 当 CWD 在被删除的 worktree 内时,命令静默失败 +- **修复:** 跑 `git worktree remove` 前先 `cd` 到主仓库根目录 + +**清理 harness 拥有的 worktree** + +- **问题:** 移除 harness 创建的 worktree 会造成幻影状态 +- **修复:** 只清理 `.worktrees/`、`worktrees/` 或 `~/.config/superpowers/worktrees/` 下的 worktree + **丢弃时不确认** + - **问题:** 意外删除工作成果 -- **修复:** 要求输入 "discard" 确认 +- **修复:** 要求输入 'discard' 确认 ## 红线 **绝不:** + - 在测试失败时继续 -- 合并前不验证测试结果 +- 合并前不验证合并结果上的测试 - 不确认就删除工作成果 - 未经明确请求就强制推送 +- 在确认合并成功之前移除 worktree +- 清理不是你创建的 worktree(按来源判断) +- 在 worktree 内部跑 `git worktree remove` **始终:** + - 在提供选项前验证测试 -- 准确展示 4 个选项 +- 展示菜单前检测环境 +- 准确展示 4 个选项(分离 HEAD 时是 3 个) - 选项 4 要求输入确认 -- 只在选项 1 和 4 时清理工作树 +- 只在选项 1 和 4 时清理 worktree +- 移除 worktree 前 `cd` 到主仓库根目录 +- 移除后跑 `git worktree prune` ## 集成 **被以下技能调用:** + - **subagent-driven-development**(步骤 7)- 所有任务完成后 - **executing-plans**(步骤 5)- 所有批次完成后 **配合使用:** + - **using-git-worktrees** - 清理由该技能创建的工作树 diff --git a/skills/using-git-worktrees/SKILL.md b/skills/using-git-worktrees/SKILL.md index a666b98..0e6d413 100644 --- a/skills/using-git-worktrees/SKILL.md +++ b/skills/using-git-worktrees/SKILL.md @@ -1,104 +1,122 @@ --- name: using-git-worktrees -description: 当需要开始与当前工作区隔离的功能开发或执行实现计划之前使用——创建具有智能目录选择和安全验证的隔离 git 工作树 +description: 当需要开始与当前工作区隔离的功能开发,或在执行实现计划之前使用——通过原生工具或 git worktree 回退机制确保隔离工作区存在 --- # 使用 Git 工作树 ## 概述 -Git 工作树创建共享同一仓库的隔离工作区,允许同时在多个分支上工作而无需切换。 +确保工作发生在隔离的工作区中。优先使用你的平台的原生 worktree 工具。仅在没有原生工具可用时,再回退到手动 git worktree。 -**核心原则:** 系统化的目录选择 + 安全验证 = 可靠的隔离。 +**核心原则:** 先检测现有隔离。然后用原生工具。再回退到 git。绝不与 harness 对抗。 **开始时宣布:** "我正在使用 using-git-worktrees 技能来建立一个隔离的工作区。" -## 目录选择流程 +## 步骤 0:检测现有隔离 -按以下优先顺序执行: - -### 1. 检查现有目录 +**创建任何东西之前,先检查你是否已经在一个隔离的工作区里。** ```bash -# 按优先顺序检查 -ls -d .worktrees 2>/dev/null # 首选(隐藏目录) -ls -d worktrees 2>/dev/null # 备选 +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) +BRANCH=$(git branch --show-current) ``` -**如果找到:** 使用该目录。如果两者都存在,`.worktrees` 优先。 - -### 2. 检查 CLAUDE.md +**Submodule 守卫:** 在 git submodule 内 `GIT_DIR != GIT_COMMON` 也为真。在判定"已经在 worktree 内"之前,先确认你不在 submodule 里: ```bash -grep -i "worktree.*director" CLAUDE.md 2>/dev/null +# 如果这条命令返回路径,说明你在 submodule 里,不是 worktree —— 按普通仓库处理 +git rev-parse --show-superproject-working-tree 2>/dev/null ``` -**如果指定了偏好:** 直接使用,无需询问。 +**如果 `GIT_DIR != GIT_COMMON`(且不是 submodule):** 你已经在一个 linked worktree 内。跳到步骤 3(项目设置)。**不要**再创建一个 worktree。 -### 3. 询问用户 +按分支状态报告: -如果没有现有目录且 CLAUDE.md 中无偏好设置: +- 在某个分支上:"已经在隔离工作区 ``,分支 ``。" +- 分离 HEAD:"已经在隔离工作区 ``(分离 HEAD,由外部管理)。完成时需要创建分支。" -``` -未找到工作树目录。我应该在哪里创建工作树? +**如果 `GIT_DIR == GIT_COMMON`(或在 submodule 内):** 你在一个普通的仓库检出里。 -1. .worktrees/(项目本地,隐藏目录) -2. ~/.config/superpowers/worktrees//(全局位置) +用户是否已经在你的 instructions 里表明过 worktree 偏好?如果没有,创建 worktree 之前先征求同意: -你倾向哪个? -``` +> "你希望我搭一个隔离的 worktree 吗?它能保护你当前分支不被改动。" -## 安全验证 +如果用户已声明过偏好,直接遵循,不再询问。如果用户拒绝同意,原地工作并跳到步骤 3。 -### 项目本地目录(.worktrees 或 worktrees) +## 步骤 1:创建隔离工作区 -**创建工作树前必须验证目录已被忽略:** +**你有两种机制。按这个顺序尝试。** -```bash -# 检查目录是否被忽略(遵循本地、全局和系统 gitignore) -git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/dev/null -``` +### 1a. 原生 Worktree 工具(首选) + +用户已经请求隔离工作区(步骤 0 已获同意)。你是否已经有创建 worktree 的方法?可能是名为 `EnterWorktree`、`WorktreeCreate` 的工具、`/worktree` 命令,或 `--worktree` 标志。如果有,用它,然后跳到步骤 3。 + +原生工具自动处理目录放置、分支创建和清理。在你已经有原生工具的情况下使用 `git worktree add`,会创建你的 harness 看不到也无法管理的"幻影状态"。 + +只有在没有原生 worktree 工具可用时,才进入步骤 1b。 + +### 1b. Git Worktree 回退 -**如果未被忽略:** +**只在步骤 1a 不适用时使用** —— 你没有可用的原生 worktree 工具。手动用 git 创建 worktree。 -根据 Jesse 的规则"立即修复坏掉的东西": -1. 在 .gitignore 中添加相应条目 -2. 提交更改 -3. 继续创建工作树 +#### 目录选择 -**为什么这很关键:** 防止意外将工作树内容提交到仓库。 +按以下优先级。明确的用户偏好始终优先于观察到的文件系统状态。 -### 全局目录(~/.config/superpowers/worktrees) +1. **检查你的 instructions 里是否声明过 worktree 目录偏好。** 如果用户已指定,不再询问直接用。 -无需 .gitignore 验证——完全在项目之外。 +2. **检查是否存在项目本地的 worktree 目录:** -## 创建步骤 + ```bash + ls -d .worktrees 2>/dev/null # 首选(隐藏目录) + ls -d worktrees 2>/dev/null # 备选 + ``` -### 1. 检测项目名称 + 找到就用。如果两者都存在,`.worktrees` 优先。 + +3. **检查是否存在全局目录:** + + ```bash + project=$(basename "$(git rev-parse --show-toplevel)") + ls -d ~/.config/superpowers/worktrees/$project 2>/dev/null + ``` + + 找到就用(兼容老的全局路径)。 + +4. **如果没有其他可参考的信息**,默认用项目根目录下的 `.worktrees/`。 + +#### 安全验证(仅项目本地目录) + +**创建 worktree 前必须验证目录已被忽略:** ```bash -project=$(basename "$(git rev-parse --show-toplevel)") +git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/dev/null ``` -### 2. 创建工作树 +**如果未被忽略:** 添加到 .gitignore,提交该改动,然后继续。 + +**为什么关键:** 防止 worktree 内容被意外提交到仓库。 + +全局目录(`~/.config/superpowers/worktrees/`)无需验证。 + +#### 创建工作树 ```bash -# 确定完整路径 -case $LOCATION in - .worktrees|worktrees) - path="$LOCATION/$BRANCH_NAME" - ;; - ~/.config/superpowers/worktrees/*) - path="~/.config/superpowers/worktrees/$project/$BRANCH_NAME" - ;; -esac - -# 创建带有新分支的工作树 +project=$(basename "$(git rev-parse --show-toplevel)") + +# 根据选定位置确定路径 +# 项目本地:path="$LOCATION/$BRANCH_NAME" +# 全局:path="~/.config/superpowers/worktrees/$project/$BRANCH_NAME" + git worktree add "$path" -b "$BRANCH_NAME" cd "$path" ``` -### 3. 运行项目设置 +**沙盒回退:** 如果 `git worktree add` 因权限错误(沙盒拒绝)失败,告诉用户沙盒阻止了 worktree 创建,你将在当前目录原地工作。然后原地运行 setup 和基线测试。 + +## 步骤 3:项目设置 自动检测并运行相应的设置命令: @@ -117,23 +135,20 @@ if [ -f pyproject.toml ]; then poetry install; fi if [ -f go.mod ]; then go mod download; fi ``` -### 4. 验证基线正常 +## 步骤 4:验证基线干净 -运行测试确保工作树初始状态干净: +运行测试确保工作区初始状态干净: ```bash -# 示例 - 使用项目对应的命令 -npm test -cargo test -pytest -go test ./... +# 使用项目对应的命令 +npm test / cargo test / pytest / go test ./... ``` -**如果测试失败:** 报告失败情况,询问是否继续或排查。 +**如果测试失败:** 报告失败,询问是继续还是排查。 **如果测试通过:** 报告就绪。 -### 5. 报告位置 +### 报告 ``` 工作树已就绪: @@ -145,74 +160,76 @@ go test ./... | 情况 | 操作 | |------|------| -| `.worktrees/` 存在 | 使用它(验证已忽略) | -| `worktrees/` 存在 | 使用它(验证已忽略) | -| 两者都存在 | 使用 `.worktrees/` | -| 都不存在 | 检查 CLAUDE.md → 询问用户 | +| 已在 linked worktree 内 | 跳过创建(步骤 0) | +| 在 submodule 内 | 按普通仓库处理(步骤 0 守卫) | +| 有原生 worktree 工具 | 用它(步骤 1a) | +| 没有原生工具 | git worktree 回退(步骤 1b) | +| `.worktrees/` 存在 | 用它(验证已忽略) | +| `worktrees/` 存在 | 用它(验证已忽略) | +| 两者都存在 | 用 `.worktrees/` | +| 都不存在 | 检查 instructions 文件,再默认 `.worktrees/` | +| 全局路径存在 | 用它(向后兼容) | | 目录未被忽略 | 添加到 .gitignore + 提交 | +| 创建时权限错误 | 沙盒回退,原地工作 | | 基线测试失败 | 报告失败 + 询问 | | 无 package.json/Cargo.toml | 跳过依赖安装 | ## 常见错误 +### 与 harness 对抗 + +- **问题:** 平台已经提供隔离的情况下还在用 `git worktree add` +- **修复:** 步骤 0 检测现有隔离。步骤 1a 让位给原生工具。 + +### 跳过检测 + +- **问题:** 在已有的 worktree 内嵌套创建另一个 worktree +- **修复:** 创建任何东西之前都先跑步骤 0 + ### 跳过忽略验证 -- **问题:** 工作树内容被跟踪,污染 git status -- **修复:** 创建项目本地工作树前始终使用 `git check-ignore` +- **问题:** worktree 内容被跟踪,污染 git status +- **修复:** 创建项目本地 worktree 前始终使用 `git check-ignore` ### 假设目录位置 -- **问题:** 造成不一致,违反项目约定 -- **修复:** 遵循优先级:现有目录 > CLAUDE.md > 询问 +- **问题:** 造成不一致、违反项目约定 +- **修复:** 遵循优先级:现有目录 > 全局历史路径 > instructions 文件 > 默认 ### 带着失败的测试继续 - **问题:** 无法区分新 bug 和已有问题 - **修复:** 报告失败,获得明确许可后再继续 -### 硬编码设置命令 - -- **问题:** 在使用不同工具的项目上会出错 -- **修复:** 从项目文件自动检测(package.json 等) - -## 示例工作流 - -``` -你:我正在使用 using-git-worktrees 技能来建立一个隔离的工作区。 - -[检查 .worktrees/ - 存在] -[验证已忽略 - git check-ignore 确认 .worktrees/ 已被忽略] -[创建工作树:git worktree add .worktrees/auth -b feature/auth] -[运行 npm install] -[运行 npm test - 47 个通过] - -工作树已就绪:/Users/jesse/myproject/.worktrees/auth -测试通过(47 个测试,0 个失败) -准备实现 auth 功能 -``` - ## 红线 **绝不:** -- 创建项目本地工作树时不验证是否已忽略 + +- 步骤 0 已检测到现有隔离时还创建 worktree +- 在已有原生 worktree 工具(如 `EnterWorktree`)的情况下还用 `git worktree add`。这是 #1 错误——有就用。 +- 跳过步骤 1a 直接跳到步骤 1b 的 git 命令 +- 不验证已忽略就创建项目本地 worktree - 跳过基线测试验证 - 不询问就带着失败的测试继续 -- 在有歧义时假设目录位置 -- 跳过 CLAUDE.md 检查 **始终:** -- 遵循目录优先级:现有目录 > CLAUDE.md > 询问 -- 对项目本地目录验证是否已忽略 + +- 先跑步骤 0 检测 +- 优先原生工具,其次 git 回退 +- 遵循目录优先级:现有目录 > 全局历史路径 > instructions 文件 > 默认 +- 项目本地目录验证已忽略 - 自动检测并运行项目设置 - 验证测试基线干净 ## 集成 **被以下技能调用:** + - **brainstorming**(阶段 4)- 设计通过且需要实现时必需 - **subagent-driven-development** - 执行任何任务前必需 - **executing-plans** - 执行任何任务前必需 - 任何需要隔离工作区的技能 **配合使用:** + - **finishing-a-development-branch** - 工作完成后清理时必需