mcpField
G
git-branch-cleanup

git-branch-cleanup

github.com/chann開発050 回インストール2 日前に更新
リポジトリ

git-branch-cleanup について

保護対象ブランチにマージ済みのローカルGitブランチを特定し、対象を削除するスキルです。保護対象と現在のブランチを残し、候補ごとの根拠を示してから確認を求めます。

主な機能

  1. 01ローカルの保護対象へのマージ済みブランチを特定
  2. 02保護対象と現在のブランチを保持
  3. 03候補ごとのマージ先を表示
  4. 04削除前に確認を要求
  5. 05安全な `git branch -d` のみ使用

活用シーン

  1. 01マージ済み作業ブランチの整理
  2. 02削除前の候補確認
  3. 03保護対象やチェックアウト中のブランチの保持

インストール

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

$npx skills add https://github.com/chann/skills --skill git-branch-cleanup

インストール後、Claude Code で/git-branch-cleanupを入力して読み込まれたか確認します。

同梱ファイルagents/openai.yamlevals/evals.json

詳細

Git ブランチのクリーンアップ

概要

保護対象ブランチのいずれかに完全にマージ済みで、安全に削除できるローカルブランチを見つけて削除します。保護対象の名前(main、master、dev、develop、development、stg、stage、staging、root)と現在のブランチは、常に保持されます。

開始時にアナウンスします:「git-branch-cleanup スキルを使用して、保護対象ブランチにすでにマージ済みのローカルブランチを削除します。」

保護対象ブランチ

以下のブランチ名は、マージ状況にかかわらず削除しません。

main、master、dev、develop、development、stg、stage、staging、root

現在のブランチも削除しません。

ワークフロー

ステップ 1:一覧を確認する
git fetch --prune 2>/dev/null || true   # informational; keeps refs honest, don't error if offline

current=$(git branch --show-current)
[ -n "$current" ] || { echo "Detached HEAD; checkout a branch first." >&2; exit 1; }

protected=(main master dev develop development stg stage staging root)

# All local branch names
all=$(git for-each-ref --format='%(refname:short)' refs/heads/)
ステップ 2:保護対象ブランチのうち、ローカルに実在するものを確認する

ローカルに存在する保護対象ブランチのみ、マージ先として使用できます。

anchors=()
for p in "${protected[@]}"; do
  git rev-parse --verify "$p" >/dev/null 2>&1 && anchors+=("$p")
done

if [ "${#anchors[@]}" -eq 0 ]; then
  echo "No protected branches (main/master/dev/develop/development/stg/stage/staging/root) found locally; nothing to anchor against." >&2
  exit 1
fi
ステップ 3:候補を特定する

以下の条件をすべて満たすブランチが候補です。

  1. 保護対象リストに含まれていない
  2. 現在のブランチではない
  3. 少なくとも 1 つのアンカーからその先端に到達できる(つまり、完全にマージ済みである)
candidates=()
for b in $all; do
  # skip protected
  case " ${protected[*]} " in *" $b "*) continue ;; esac
  # skip current
  [ "$b" = "$current" ] && continue
  # merged into any anchor?
  for a in "${anchors[@]}"; do
    if git merge-base --is-ancestor "$b" "$a"; then
      candidates+=("$b|$a")   # remember which anchor proved it
      break
    fi
  done
done

各エントリには branch|anchor を保存し、各候補をなぜ削除するのか計画で示せるようにします。

ステップ 4:計画を提示して確認する
Plan: delete N merged local branches

  feature/oauth-login        (merged into main)
  bugfix/null-response       (merged into main)
  chore/update-deps          (merged into develop)

Kept (protected or current):
  main, develop, stage  ← protected
  feature/in-progress  ← current branch

Proceed? (y/N)

candidates が空の場合 →「クリーンアップ対象はありません。マージ済みの保護対象外ブランチは見つかりませんでした。」とユーザーに伝えて終了します。

明示的な確認を待ちます。既定値はいいえです。

ステップ 5:-d で安全に削除する
for entry in "${candidates[@]}"; do
  branch="${entry%%|*}"
  if git branch -d "$branch"; then
    echo "✓ deleted $branch"
  else
    echo "✗ refused $branch — left intact (run \`git branch -d $branch\` manually if you're sure)"
  fi
done

-D(強制)は絶対に使用しないでください。マージ済みだと判断した候補に対して -d が拒否した場合は、何かがおかしいため、報告してスキップします。強制削除に切り替えてはいけません。

ステップ 6:概要
git branch                # show what remains
echo "Done. Deleted M of N candidates."

スキップした候補がある場合は、そのブランチを列挙し、-d に拒否されたことを説明します(アンカーから実際には到達できないコミットがブランチに含まれている可能性があります。例:--no-commit による cherry-pick や、書き換えられた履歴)。

実例

User: 머지된 브랜치 다 정리해줘

current = main
anchors found locally: main, develop

Local branches:
  main                       ← protected, kept
  develop                    ← protected, kept
  feature/oauth-login        → ancestor of main? yes → candidate
  bugfix/null-response       → ancestor of main? yes → candidate
  feature/wip-experiment     → ancestor of any anchor? no → kept (not yet merged)
  hotfix/typo                → ancestor of develop? yes → candidate

Plan: delete 3 (feature/oauth-login, bugfix/null-response, hotfix/typo)
User confirms.
→ git branch -d feature/oauth-login    ✓
→ git branch -d bugfix/null-response   ✓
→ git branch -d hotfix/typo            ✓
→ Show remaining branches: main, develop, feature/wip-experiment.

注意すべき点

絶対に行わないこと:

  • git branch -D(強制削除)を使うこと。このスキルで許可されているのは -d(安全な削除)のみです
  • 保護対象リスト(main、master、dev、develop、development、stg、stage、staging、root)内のブランチを削除すること
  • 現在のブランチを削除すること
  • リモートブランチを削除すること(git push origin --delete ...)。このスキルの対象はローカルのみです
  • 確認プロンプトを省略すること
  • マージされていない古いブランチを候補として扱うこと。候補となるのは完全にマージ済みのブランチのみです

必ず行うこと:

  • 各候補の根拠となるアンカーを示したうえで計画を提示する(ユーザーが確認できるようにするため)
  • 保持したブランチとその理由を示す
  • マージ状況の確認には git merge-base --is-ancestor を使う(HEAD とのマージ状況しか確認しない git branch --merged は使わない)
  • 確認の既定値を「いいえ」にする

よくある間違い

--is-ancestor の代わりに git branch --merged を使う

  • 問題: --merged が確認するのは現在のブランチに対するマージ状況のみで、すべての保護対象アンカーに対してではありません
  • 対処: アンカーごとに git merge-base --is-ancestor を実行します。そうすれば、main にはマージされていなくても develop にマージ済みのブランチを検出できます

-d が拒否したときに強制削除する

  • 問題: 安全確認がリスクを正しく検出しているにもかかわらず、-D を使ってしまうことです
  • 対処: そのブランチをスキップして報告し、ユーザーの判断に委ねます

現在のブランチを候補に含める

  • 問題: 現在チェックアウトしているブランチは削除できず、Git にも拒否されます
  • 対処: 候補リストを作成する前に、現在のブランチを除外します

連携

併用するスキル:

  • git-merge-to-main / git-merge-to-dev — これらのスキルはマージ直後に単一のソースブランチを削除します。このスキルは、すでにマージ済みのブランチをすべてクリーンアップします

呼び出し元: ユーザーが手動で呼び出した場合のみです。他のスキルのワークフロー中に自動実行してはいけません。

コメント