| name | cc-sdd-restack-after-merge |
| description | stacked PRの下位PRがマージされた後に上位branchをrestack(rebase/cherry-pick再構成)する際に使用。「restackして」「上位PRを更新して」「restack after merge」「PRのbaseを更新」「スタックを整理」という依頼でトリガーする。対象sliceの特定→rebase→変更ファイル確認と代表テスト実行→force-with-leaseでpush→PR base更新→auto-merge判定の順で進める。 |
| disable-model-invocation | true |
cc-sdd Restack After Merge
cc-sdd-review-slice-stack で作成した stacked PR の下位 PR がマージされた後、上位 branch を rebase して PR の base を更新する。条件を満たした PR には auto-merge を設定する。
全体フロー内の位置
cc-sdd-review-slice-stack: stacked draft PR を作成
- 人間が bottom PR をレビュー・マージ
- 本スキル: 上位 branch を restack、PR base 更新、auto-merge 設定
- 2〜3 を繰り返す
- 全 slice マージ後、統合 PR(review trunk → main)で最終判断
前提条件
cc-sdd-review-slice-stack で作成した stacked PR が存在すること
- 少なくとも 1 つの下位 PR がマージ済みであること
gh auth status が通ること
- git working tree が clean であること
Step 1: 現状認識
$implBranch = git branch --show-current
$defaultBranch = gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'
# review slice branch 一覧を取得
$reviewBranches = git branch -r --list "origin/review/*" | ForEach-Object { $_.Trim() }
# マージ済みPRとオープンPRの特定
$openPRs = gh pr list --json number,headRefName,baseRefName,state --jq '.[] | select(.headRefName | startswith("review/"))'
以下を報告する。
- review trunk branch 名
- 各 slice branch の状態(merged / open / draft)
- マージ済み slice の一覧
- 未マージ slice の一覧と現在の base
Step 2: restack 対象の特定
マージ済みの直上にある未マージ slice branch を特定する。
# 例: slice 01 がマージ済み → slice 02 の base が stale
# slice 02 の新しい base は review trunk(slice 01 のコミットがマージ済み)
| 条件 | 対象にする slice | 新しい base | 次の動作 |
|---|
| 最下位の未マージ slice の直下がマージ済み | その slice | review trunk | rebase を実行 |
| 直下の slice が未マージ | なし | 変更なし | その slice はスキップ |
| 複数 slice が連続でマージ済み | 連続区間の直上にある最初の未マージ slice | review trunk | その 1 つだけ rebase してから上位へ連鎖更新 |
| すべてマージ済み | なし | なし | 統合 PR の状態確認へ進む |
restack 順序
- bottom から順に処理する
- 直下がまだマージされていない slice はスキップ
- 複数の slice が連続でマージ済みなら、その直上の 1 つだけ restack
Step 3: rebase 実行
# 対象 slice branch をチェックアウト
git fetch origin
git checkout "review/<impl_branch>/02-<slice-key>"
# 新しい base に rebase
git rebase "origin/review/<impl_branch>/trunk"
conflict 発生時は、解決方法が明確な場合に限り解消して継続する。 片側の変更を採用すれば整合する場合、rename 追従のみの場合、generated file の再生成で整合する場合など、判断根拠を説明できるケースに限る。
- conflict を解消したら
git add <file> の後に git rebase --continue で継続する
- conflict を解消して進めた場合は、対象ファイル・採用した解決内容・判断根拠を Step 8 で必ず報告する
解決方針が不明確な場合のみ停止する。 停止時は以下を報告して手動解決を求める。
- conflict のあるファイル一覧(
git diff --name-only --diff-filter=U)
- conflict 内容の要約
- 提示可能な解決方法と判断根拠
Step 4: 軽量検証
rebase 後に以下を実行する。
git diff --name-only origin/<rebase前のbase>...HEAD で変更ファイル一覧を確認
- 変更範囲に対応する代表テストを 1 つ以上実行する
- テスト候補が複数ある場合は、変更ファイルに最も近い unit test を優先し、候補がなければ関連 integration test か
make check-all を実行する
- 検証に失敗した場合は push せず停止し、失敗したコマンドと要約だけを報告する
Step 5: push と PR base 更新
# rebase 後の branch を force push
git push origin "review/<impl_branch>/02-<slice-key>" --force-with-lease
# PR の base を更新(下位 branch → マージ先に変更)
gh pr edit <pr-number> --base "review/<impl_branch>/trunk"
--force-with-lease を使い、他者の push を上書きしないよう保護する。
上位 slice の連鎖更新
slice 02 の rebase 後、slice 03 以降も同様に処理する。
# slice 03 の base を slice 02 に rebase
git checkout "review/<impl_branch>/03-<slice-key>"
git rebase "origin/review/<impl_branch>/02-<slice-key>"
git push origin "review/<impl_branch>/03-<slice-key>" --force-with-lease
全未マージ slice について bottom から順に繰り返す。
Step 6: auto-merge 設定
以下の条件をすべて満たす PR に auto-merge を設定する。
auto-merge 条件
- PR が draft でないこと(
gh pr ready 済み)
- CI が通っていること
- レビュー承認済みであること
設定コマンド
# 条件を確認
$pr = gh pr view <pr-number> --json isDraft,reviewDecision,statusCheckRollup
# isDraft: false, reviewDecision: APPROVED, checks: all passing
# auto-merge を有効化
gh pr merge <pr-number> --auto --squash
条件を満たさない PR には auto-merge を設定しない。 理由を報告する。
auto-merge が設定できない場合
- リポジトリで auto-merge が無効の場合: Settings → General → Allow auto-merge の有効化が必要
- 必要な status checks が未設定の場合: branch protection rule の設定が必要
- いずれの場合も手順を報告し、手動マージの代替手順を提示する
Step 7: 作業用 worktree の安全解除
このスキル実行中に一時 worktree を作成した場合、完了時に必ず解除する。
7.1 解除対象の管理
- 一時 worktree を作成した時点で、解除対象パスを配列で保持する(例:
$createdWorktrees += "<path>")。
- 解除対象はこのスキルが作成した一時 worktree のみとする。
7.2 安全解除手順
foreach ($wt in $createdWorktrees) {
if (Test-Path $wt) {
$dirty = git -C $wt status --short
if ($dirty) {
Write-Output "SKIP_REMOVE_DIRTY_WORKTREE: $wt"
continue
}
# rebase/merge/cherry-pick など進行中メタデータがある場合は解除しない
$gitDir = git -C $wt rev-parse --git-dir
if (Test-Path (Join-Path $gitDir "rebase-merge") -or
Test-Path (Join-Path $gitDir "rebase-apply") -or
Test-Path (Join-Path $gitDir "MERGE_HEAD") -or
Test-Path (Join-Path $gitDir "CHERRY_PICK_HEAD")) {
Write-Output "SKIP_REMOVE_IN_PROGRESS_WORKTREE: $wt"
continue
}
git worktree remove "$wt"
}
}
# 消えたディレクトリを参照する stale エントリを掃除
git worktree prune -v
7.3 解除確認
git worktree list を実行し、解除対象が残っていないことを確認する。
- 残っている場合は「理由(dirty / in-progress / remove失敗)」と手動解除手順を最終報告に明記する。
Step 8: 最終報告
以下を一覧で出力する。
- restack した slice branch 一覧
- 各 branch の rebase 結果(成功 / conflict 解消 / 停止)
- conflict を解消して進めた場合の解決内容(対象ファイル / 採用した変更 / 判断根拠)
- 更新した PR の base 変更内容
- auto-merge 設定結果(設定済み / 条件未達の理由)
- worktree 解除結果(解除済み / スキップ理由 / 手動解除要否)
- 残りの未マージ slice 一覧
- 次のアクション(「次のレビュー対象は Slice N です」等)
全 slice マージ完了時
全 slice がマージされた場合は追加で以下を報告する。
- 統合 PR(review trunk →
$defaultBranch)の状態
- 統合 PR を ready にして最終レビューを依頼するかの確認
# 統合 PR を ready に変更
gh pr ready <integration-pr-number>
禁止事項
- 現在ブランチ(
$implBranch)の履歴を変更すること
- 解決方針が不明確な conflict を推測で解決して進めること
--force-with-lease なしで force push すること
- auto-merge 条件を満たさない PR に auto-merge を設定すること
- レビュー未承認の PR を ready にすること
- このスキルが作成した作業用 worktree を解除せずに終了すること