mcpField
S
squash-merge-and-clean-up

squash-merge-and-clean-up

github.com/mtngtools開発041 回インストール3 週間前に更新
リポジトリ

squash-merge-and-clean-up について

squash-merge-and-clean-upは、人間が名前を指定して起動するスキルで、セッションのPRを取り込み、そのセッションが作成したワークツリーとブランチを削除します。セッション所有物の整理と共有メインチェックアウトの更新を、別々の承認段階に分けます。

主な機能

  1. 01PRの状態、チェック、ワークツリー、ブランチの確認
  2. 02具体的なマージ計画の提示と承認
  3. 03スカッシュマージとAPIによる検証
  4. 04このセッションが作成したものだけを削除
  5. 05メインチェックアウト更新の個別承認

活用シーン

  1. 01明示的な承認後にセッションのPRをマージ
  2. 02セッションのワークツリーとブランチを整理
  3. 03承認後に共有チェックアウトを更新

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mtngtools/agents --skill squash-merge-and-clean-up

インストール後、Claude Code で/squash-merge-and-clean-upを入力して読み込まれたか確認します。

詳細

squash-merge-and-clean-up

人間専用。 人間から名前を指定して依頼された場合にのみ、これを開始してください。別のスキルからここに到達した場合は、停止し、いずれかの手順を実行する前に明示的な確認を得てください。

このセッションで開いた PR をマージし、このセッションで作成したものを片付けます。作業ツリーを切り替え、スカッシュマージし、両方のブランチを削除して、作業ツリーを削除します。

一貫してセッションの範囲内で作業します。 同じリポジトリでは、ほかのエージェントセッションも並行して実行されており、それらの作業ツリーやブランチも同じ一覧に表示されます。このセッションが作成したもの、つまりこのセッションが入った作業ツリー、プッシュしたブランチ、開いた PR だけを対象にしてください。それ以外は、誰かが作業中のものです。

所有範囲で分けた二つのゲート。 ゲート1では、このセッションが所有するすべてのもの、つまりマージと、このセッション自身の作業ツリーおよびブランチの削除を扱います。ゲート2では、共有状態に触れる唯一の手順、すべてのセッションが参照するプライマリチェックアウトを最新の状態にする作業を扱います。

1. 確認

情報を収集し、計画を立てるために保持します。

  • gh pr view <n> --json number,title,body,state,mergeable,mergeStateStatus,headRefName,baseRefName,closingIssuesReferences
  • gh pr checks <n> — ドキュメントのみの PR ではチェックがないと表示されることがありますが、これは失敗ではなく合格です
  • git worktree list — このセッションが作成したエントリを確認します。locked は別のセッションのものを示します
  • git branch -vv — + プレフィックスは、いずれかの作業ツリーでチェックアウトされているブランチを示します

計画を立てる前に PR の本文を修正し、計画を立てた後に修正してはいけません。 リンクされた Issue を閉じるのはマージなので、キーワードが欠けていると Issue は閉じられず、後で誰かが手動で閉じることになります。この PR で Issue を閉じる予定なのに、closingIssuesReferences が空であるか、いずれかの Issue が含まれていない場合は、gh pr edit <n> --body を使って、既存の本文を残したまま追記し、Issue ごとに Closes #{issue} を1行追加してください。Issue 番号はブランチ名、コミット、または本文に書かれた内容から確認します。番号を推測してはいけません。また、このブランチで実際に閉じない Issue をリンクしてはいけません。ここで閉じる Issue がない場合は通常の PR なので、変更は不要です。編集後に本文を読み直し、マージによって閉じられる Issue を計画に明記してください。

2. ゲート1:計画を表示してから確認を求める

計画は二つの経路で提示します。片方だけでは不十分だからです。 ツール呼び出しの直前に出力したテキストは、ハーネスに飲み込まれて表示されず、計画がないまま質問だけが届くことがあります。また、質問欄はリスト形式にならず、プレーンな段落として表示されるため、計画をそこに入れると読みにくくなります。人間が最も慎重に読む必要があるときに、まさにその状態になります。そこで、通常の出力として計画を表示し、会話記録に残すと同時に、同じ計画を各選択肢の preview に含めます。質問 UI では選択肢の横に表示されます。ハーネスがどちらの経路を採用しても、質問を受けるときに計画が画面に表示されます。

手順3〜5の計画を PLAN: 見出しの下に番号付きリストとして出力し、実際の PR 番号、ブランチ名、作業ツリーのパスを明記します。プレースホルダーは使ってはいけません。

PLAN:
1. Exit the worktree at `<path>`, returning to the primary checkout
2. Squash-merge <PR title> (#<n>) into `<base>` as `<commit subject>`, closing #<issue>
3. Confirm from the API that it merged, and that the branch's content landed
4. Remove the worktree at `<path>`
5. Delete `<branch>` locally and on origin

2行目の終了条項には、本文でリンクされているすべての Issue を記載します。Issue がリンクされていない場合は、その条項全体を省略します。

次の文言で、AskUserQuestion を使って質問を一つだけ行います。

プレビューに表示されたスカッシュマージ計画を実行しますか?

選択肢は はい、実行する、いいえ、ここで停止する、計画が表示されていません。もう一度出力してください。 です。すべての選択肢の preview に、PLAN: のリスト全体を含めます。上記の出力からそのままコピーし、決して書き直したり、短縮したり、要約したりしてはいけません。一つのテキストを二つの経路で提示し、コピーの内容に食い違いが生じないようにします。プレビュー以外では、計画の内容を質問文、選択肢のラベル、選択肢の説明に含めてはいけません。計画の短いコピーを別に作ると、二つの内容が食い違うおそれがあります。

計画が表示されていません が選択された場合、どちらの経路でも計画が表示されなかったことになります。PLAN: リスト全体をもう一度出力し、そこでターンを終了してください。計画を最後のメッセージとし、その後にツール呼び出しを行ってはいけません。ハーネスが常に表示するのはこの位置だけです。人間が応答した後に限り、同じ質問をもう一度行います。はいの場合にのみ続行します。

3. まずワークツリーを離れる

マージする前にワークツリーを離れ、セッションをプライマリチェックアウトに戻します。

この手順の要点は、この順序にあります。 ワークツリー内から gh pr merge を実行すると、サーバー側ではマージが完了した後、ローカルでは fatal: '<base>' is already used by worktree at … というエラーで失敗します。これは、ローカルでベースブランチをチェックアウトしようとしますが、そのブランチはプライマリチェックアウトで使用中だからです。マージが成功しているのに終了コードはゼロ以外となり、--delete-branch も実行されません。再試行するのはもっともらしい対処に見えますが、誤りです。PR はすでにマージされています。

作業ディレクトリをプライマリチェックアウトに戻して、ワークツリーを離れてください。手段はハーネスが提供する方法で構いません。ワークツリーはディスク上に残してください。ワークツリーを削除するのは、その内容が取り込まれたことを確認した後の手順 5 であり、それより前ではありません。ハーネスに移動手段がない場合は、ワークツリー内からではなく、明示的なパスを指定してマージしてください(git -C <primary-checkout> … と gh -R <owner/name>)。Claude Code の場合は、action: "keep" を指定して ExitWorktree を実行します。

4. Squash マージしてから検証する

gh pr merge <n> --squash --subject "<type>(<scope>): <subject> (#<issue>) (#<pr>)"

サブジェクトは、リポジトリの規約に従います。コミット規約に沿ったサブジェクト、Issue 番号、PR 番号の順です。

終了コードではなく、API から確認してください。

gh pr view <n> --json state,mergedAt,mergeCommit

state: MERGED で mergeCommit.oid があることが完了の基準です。マージ済みと表示されていれば、コマンドの終了結果にかかわらずマージは完了しています。

5. このセッションで作成したものを削除する

事前条件を満たしたうえで、次の各項目を明示した順序で実行します。

  1. 失われるものがないことを確認する — git fetch origin --prune を実行してから、git diff --stat <worktree-HEAD> origin/<base> を実行します。差分が空であれば、Squash マージによって内容が取り込まれたことを確認できます。ローカルコミットは削除時に破棄されるため、削除後ではなく、削除前に確認してください。
  2. ワークツリーを削除する — git worktree remove <path> を実行してから、git worktree prune を実行します。locked とマークされた項目や、このセッションで作成していない項目はスキップしてください。サブモジュールが配置されているワークツリーは、クリーンな状態でも通常の削除を拒否します。まず git -C <path> status で、サブモジュール内に変更がないことを確認し、その後 --force を付けて削除してください。
  3. ローカルブランチを削除する — git branch -D <branch> を実行します。ブランチは手順 2 で解放されます。ワークツリーでチェックアウト中のブランチは削除できません。
  4. リモートブランチを削除する — git push origin --delete <branch> を実行します。マージ時に --delete-branch が実行されなかった場合は、手動で削除してください。

6. 第 2 段階:メインのチェックアウトを最新にする

ここまでの操作では、このセッション自体の状態だけに触れています。この手順では、すべての同時実行セッションで共有されるチェックアウトを変更するため、第 1 段階で「はい」と回答済みでも、別途確認します。

第 1 段階と同じ形式で、どちらのルートでも、計画を通常の出力として表示し、すべての選択肢の preview にもそのまま含めます。チェックアウトの現在の状態を表示してください。現在のブランチ、作業ツリーがクリーンかどうか、origin/<base> からどれだけ遅れているか、そして更新時に対処が必要になる未コミットの変更があれば、その内容を示します。

サブモジュール:古くてもダーティとは限りません。 サブモジュールを含むリポジトリでは、git status の M <submodule> には 2 つの異なる意味があり、計画でどちらなのかを示す必要があります。git submodule status で区別できます。+ プレフィックスは、チェックアウトのコミットがブランチに記録されているものと異なることを示します。ブランチを切り替えてもサブモジュールのチェックアウトは切り替わらないために残された、古いポインターです。一方、サブモジュール内の変更済みまたは未追跡のファイル(git -C <submodule> status)は実際の作業です。古いポインターはチェックアウトが遅れていることを意味するため、この手順の計画に同期を含めます。サブモジュール内の実際の作業は、別のセッションまたは人間の担当です。その内容を明示し、残したままにして、そのサブモジュールを同期対象から除外してください。

PLAN:
- Primary checkout is on `<branch>`, <clean | N uncommitted files>, <N> behind `origin/<base>`
- Fast-forward it to `origin/<base>` (`<sha>`) with `git merge --ff-only`
- Sync stale submodule checkouts to the recorded pointers with `git submodule update --init`

同期の行は、リポジトリにサブモジュールがある場合にのみ表示します。この手順をそこで完了させるために必要です。早送りマージではブランチに記録されているポインターが更新されますが、各サブモジュールのチェックアウトはそのままです。そのため、両方の操作を実行して初めてチェックアウトが最新になります。特定のサブモジュールをそのままにしておく必要がある場合は、パスを指定して同期します(git submodule update --init -- <path>)。

次の質問を 1 つだけします。

プレビューに表示したとおり、メインのチェックアウトを最新にしますか?

選択肢は はい、実行する と いいえ、そのままにする です。どちらにも、完全な PLAN: リストを preview として含めます。「はい」の場合、チェックアウトがクリーンで(古いサブモジュールポインターはクリーンとして扱います)、0 だけ先行しているときに限り、git merge --ff-only origin/<base> を実行し、その後で計画に記載したサブモジュールの同期を行います。「いいえ」は正常な終了であり、失敗ではありません。

最後に、削除したものと残っているものを報告します。自分が作成していない未追跡ファイルや、locked 状態のワークツリーは、別のセッションまたは人間の担当です。その内容を明示し、残したままにしてください。

コメント