|
| 1 | +--- |
| 2 | +name: sync-worktree |
| 3 | +description: 在多个 git worktree 分支之间同步代码(rebase)。支持状态概览、单分支同步、批量同步、自定义基准分支。 |
| 4 | +license: MIT |
| 5 | +metadata: |
| 6 | + author: mudssky |
| 7 | + version: "1.0" |
| 8 | +--- |
| 9 | + |
| 10 | +在多个 git worktree 分支之间通过 rebase 同步代码。 |
| 11 | + |
| 12 | +**输入**: `/sync-worktree` 后的参数决定运行模式: |
| 13 | + |
| 14 | +| 用法 | 说明 | |
| 15 | +|------|------| |
| 16 | +| `/sync-worktree` | 状态概览:显示所有 worktree 的同步状态 | |
| 17 | +| `/sync-worktree <branch>` | 单分支同步:将指定分支 rebase 到 master | |
| 18 | +| `/sync-worktree <branch> --from <base>` | 自定义基准:将指定分支 rebase 到 `<base>` | |
| 19 | +| `/sync-worktree --all` | 批量同步:将所有 feature worktree rebase 到 master | |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## Step 1: 发现 Worktree |
| 24 | + |
| 25 | +执行以下命令发现所有 worktree: |
| 26 | + |
| 27 | +```bash |
| 28 | +git worktree list --porcelain |
| 29 | +``` |
| 30 | + |
| 31 | +解析输出,构建 worktree 列表。每个 worktree 条目包含: |
| 32 | +- `worktree <path>` — 文件系统路径 |
| 33 | +- `HEAD <sha>` — 当前 commit |
| 34 | +- `branch refs/heads/<name>` — 分支名 |
| 35 | + |
| 36 | +列表中的**第一个** worktree 是**主 worktree**。提取其分支名作为**默认基准分支**(通常是 `master` 或 `main`)。 |
| 37 | + |
| 38 | +将所有 worktree 存储为列表:`{ path, branch, head }`。 |
| 39 | + |
| 40 | +--- |
| 41 | + |
| 42 | +## Step 2: 解析参数 |
| 43 | + |
| 44 | +从用户输入(ARGUMENTS 字符串)中判断模式: |
| 45 | + |
| 46 | +1. **无参数** → 状态概览模式(跳转 Step 3) |
| 47 | +2. **`--all`** → 批量同步模式(跳转 Step 6) |
| 48 | +3. **`<branch>`** → 单分支同步模式 |
| 49 | + - 检查是否同时提供了 `--from <base>`;如果有,使用该分支替代默认基准 |
| 50 | + - 跳转 Step 4 |
| 51 | + |
| 52 | +--- |
| 53 | + |
| 54 | +## Step 3: 状态概览(无参数) |
| 55 | + |
| 56 | +对每个 worktree 收集以下信息: |
| 57 | + |
| 58 | +1. **相对于基准分支的领先/落后数**:对每个 feature worktree 执行: |
| 59 | + ```bash |
| 60 | + git rev-list --left-right --count <base>...<branch> |
| 61 | + ``` |
| 62 | + 输出格式:`<ahead>\t<behind>`(left = 基准领先数,right = 分支领先数)。 |
| 63 | + - "ahead" = 该分支独有的 commit 数(基准没有的) |
| 64 | + - "behind" = 基准独有的 commit 数(需要同步的) |
| 65 | + |
| 66 | +2. **工作区状态**:对每个 worktree 执行: |
| 67 | + ```bash |
| 68 | + git -C <worktree-path> status --porcelain |
| 69 | + ``` |
| 70 | + 输出为空 = clean;非空 = dirty。 |
| 71 | + |
| 72 | +以表格形式展示: |
| 73 | + |
| 74 | +``` |
| 75 | +┌─ Worktree Status ───────────────────────────────────────────────┐ |
| 76 | +│ │ |
| 77 | +│ Branch Path vs <base> │ |
| 78 | +│ ────── ──── ───────── │ |
| 79 | +│ master ✦ /path/to/main (base) │ |
| 80 | +│ aifeat /path/to/aifeat-worktree ↑1 ↓2 ✔ │ |
| 81 | +│ hotfix /path/to/hotfix-worktree ↑0 ↓3 ⚠ dirty│ |
| 82 | +│ │ |
| 83 | +│ ✦ = 当前所在 worktree │ |
| 84 | +│ ↑ = 领先(自己独有的 commit) │ |
| 85 | +│ ↓ = 落后(需要同步的 commit) │ |
| 86 | +│ ✔ = clean ⚠ = dirty │ |
| 87 | +└─────────────────────────────────────────────────────────────────┘ |
| 88 | +``` |
| 89 | + |
| 90 | +如果没有 feature worktree(只有主 worktree),显示: |
| 91 | +> 当前没有可同步的 feature worktree。使用 `git worktree add` 创建新的 worktree。 |
| 92 | +
|
| 93 | +**状态概览模式到此结束。** |
| 94 | + |
| 95 | +--- |
| 96 | + |
| 97 | +## Step 4: 单分支同步 |
| 98 | + |
| 99 | +### 4.1 验证目标分支 |
| 100 | + |
| 101 | +检查指定的分支名是否存在于 worktree 列表中。如果不存在,报错并列出所有可用的 worktree 分支供用户选择。 |
| 102 | + |
| 103 | +如果指定了 `--from <base>`,验证该基准分支在本地是否存在: |
| 104 | +```bash |
| 105 | +git rev-parse --verify <base> |
| 106 | +``` |
| 107 | +如果不存在,报错提示。 |
| 108 | + |
| 109 | +### 4.2 检查工作区状态 |
| 110 | + |
| 111 | +```bash |
| 112 | +git -C <worktree-path> status --porcelain |
| 113 | +``` |
| 114 | + |
| 115 | +如果输出**非空**,**拒绝**同步: |
| 116 | +> ❌ `<branch>` 工作区有未提交改动,请先 commit 或 stash 后重试。 |
| 117 | +
|
| 118 | +**不得继续执行。** 不要提供自动 stash 的选项。 |
| 119 | + |
| 120 | +### 4.3 检查是否已是最新 |
| 121 | + |
| 122 | +检查基准分支是否有该分支没有的 commit: |
| 123 | +```bash |
| 124 | +git rev-list --count <branch>..<base> |
| 125 | +``` |
| 126 | + |
| 127 | +如果计数为 **0**,说明该分支已包含基准的所有 commit: |
| 128 | +> ℹ `<branch>` 已是最新,无需同步。 |
| 129 | +
|
| 130 | +**到此结束。** |
| 131 | + |
| 132 | +### 4.4 同步预览 |
| 133 | + |
| 134 | +展示将要应用的 commit: |
| 135 | +```bash |
| 136 | +git log --oneline <branch>..<base> |
| 137 | +``` |
| 138 | + |
| 139 | +显示格式: |
| 140 | +``` |
| 141 | +将 rebase <branch> onto <base> |
| 142 | +
|
| 143 | +落后 <N> 个 commit: |
| 144 | + <sha1> <message1> |
| 145 | + <sha2> <message2> |
| 146 | + ... |
| 147 | +``` |
| 148 | + |
| 149 | +### 4.5 执行 Rebase |
| 150 | + |
| 151 | +```bash |
| 152 | +git -C <worktree-path> rebase <base> |
| 153 | +``` |
| 154 | + |
| 155 | +**如果 rebase 成功** → 跳转 Step 5(成功报告) |
| 156 | + |
| 157 | +**如果 rebase 失败(冲突)** → 跳转 Step 4.6(冲突处理) |
| 158 | + |
| 159 | +### 4.6 冲突处理(单分支模式) |
| 160 | + |
| 161 | +当 rebase 产生冲突时: |
| 162 | + |
| 163 | +1. 列出冲突文件: |
| 164 | + ```bash |
| 165 | + git -C <worktree-path> diff --name-only --diff-filter=U |
| 166 | + ``` |
| 167 | + |
| 168 | +2. 使用 **AskUserQuestion** 向用户提供三个选项: |
| 169 | + |
| 170 | + | 选项 | 说明 | |
| 171 | + |------|------| |
| 172 | + | Claude 协助解决 | 读取冲突文件,分析冲突内容,提出解决方案 | |
| 173 | + | 手动解决后继续 | 用户自行解决冲突,之后告知 Claude 执行 `git -C <path> rebase --continue` | |
| 174 | + | 中止 rebase | 执行 `git -C <path> rebase --abort`,恢复到同步前状态 | |
| 175 | + |
| 176 | + **如果用户选择「Claude 协助解决」**: |
| 177 | + - 读取每个冲突文件 |
| 178 | + - 分析冲突标记(`<<<<<<<`、`=======`、`>>>>>>>`) |
| 179 | + - 提出解决方案并应用编辑 |
| 180 | + - 暂存已解决的文件:`git -C <path> add <file>` |
| 181 | + - 继续 rebase:`git -C <path> rebase --continue` |
| 182 | + - 如果出现更多冲突,重复以上流程 |
| 183 | + |
| 184 | +--- |
| 185 | + |
| 186 | +## Step 5: 成功报告(单分支模式) |
| 187 | + |
| 188 | +rebase 成功后,获取信息并展示: |
| 189 | + |
| 190 | +```bash |
| 191 | +# 获取新 HEAD |
| 192 | +git -C <worktree-path> rev-parse --short HEAD |
| 193 | +``` |
| 194 | + |
| 195 | +```bash |
| 196 | +# 检查是否存在远程跟踪分支,判断是否需要 force push |
| 197 | +git -C <worktree-path> rev-parse --abbrev-ref --symbolic-full-name @{upstream} 2>/dev/null |
| 198 | +``` |
| 199 | + |
| 200 | +报告格式: |
| 201 | +``` |
| 202 | +✔ <branch> 已同步到 <base> |
| 203 | +
|
| 204 | + 新 HEAD: <short-sha> <message> |
| 205 | + 同步 commit: <N> 个 |
| 206 | + 远程分支: <upstream>(需要 force push)| 无远程跟踪分支 |
| 207 | +``` |
| 208 | + |
| 209 | +如果该分支有远程跟踪分支,提醒: |
| 210 | +> ⚠ 该分支有远程跟踪分支,rebase 后需要 `git push --force-with-lease` 来更新远程。 |
| 211 | +
|
| 212 | +--- |
| 213 | + |
| 214 | +## Step 6: 批量同步(`--all`) |
| 215 | + |
| 216 | +### 6.1 枚举同步目标 |
| 217 | + |
| 218 | +从 worktree 列表(Step 1)中选取所有**非主 worktree**,作为同步目标。 |
| 219 | + |
| 220 | +如果没有 feature worktree: |
| 221 | +> 当前没有可同步的 feature worktree。 |
| 222 | +
|
| 223 | +### 6.2 逐个处理分支 |
| 224 | + |
| 225 | +对每个 feature worktree 执行单分支同步流程(Step 4.1–4.5),但有以下区别: |
| 226 | + |
| 227 | +- **脏工作区** → 记录为 `⚠ 跳过(脏工作区)`,继续处理下一个分支 |
| 228 | +- **已是最新** → 记录为 `ℹ 已是最新`,继续处理下一个分支 |
| 229 | +- **rebase 冲突** → 执行 `git -C <path> rebase --abort`,记录为 `❌ 跳过(冲突)`,继续处理下一个分支 |
| 230 | +- **成功** → 记录为 `✔ 成功`,继续处理下一个分支 |
| 231 | + |
| 232 | +**不要因任何单个分支的失败而停止。** 始终处理所有分支。 |
| 233 | + |
| 234 | +### 6.3 汇总报告 |
| 235 | + |
| 236 | +所有分支处理完毕后,显示汇总表格: |
| 237 | + |
| 238 | +``` |
| 239 | +┌─ Sync Summary ──────────────────────────────────────────────┐ |
| 240 | +│ │ |
| 241 | +│ Branch Status Detail │ |
| 242 | +│ ────── ────── ────── │ |
| 243 | +│ aifeat ✔ 成功 同步了 3 个 commit │ |
| 244 | +│ hotfix ⚠ 跳过 脏工作区 │ |
| 245 | +│ experiment ❌ 跳过 rebase 冲突 │ |
| 246 | +│ docs ℹ 已是最新 — │ |
| 247 | +│ │ |
| 248 | +│ 结果: 1 成功 / 1 跳过(脏) / 1 跳过(冲突) / 1 已是最新 │ |
| 249 | +└─────────────────────────────────────────────────────────────┘ |
| 250 | +``` |
| 251 | + |
| 252 | +如果有因冲突被跳过的分支,补充提示: |
| 253 | +> ⚠ 冲突分支可单独处理:`/sync-worktree <branch>` 后手动解决冲突。 |
| 254 | +
|
| 255 | +--- |
| 256 | + |
| 257 | +## 安全护栏 |
| 258 | + |
| 259 | +- **禁止自动 stash**:工作区有未提交改动时,直接拒绝并告知用户先 commit 或 stash。 |
| 260 | +- **禁止执行 `git push`**:本 skill 仅做本地 rebase。如需 force push,只提醒用户,不代为执行。 |
| 261 | +- **禁止使用 `git rebase -i`**:交互式 rebase 需要终端输入,不受支持。 |
| 262 | +- **批量模式冲突必须 abort**:`--all` 模式下遇到冲突时,始终执行 `git rebase --abort` 并跳过。 |
| 263 | +- **始终验证分支存在性**:在执行任何操作前,确认目标分支存在于 worktree 列表中。 |
0 commit comments