git-branch-cleanup について
ローカル Git ブランチを安全に整理・削除するためのエージェントスキルです。マージ状態、リモート追跡、古さで分類し、削除前に安全確認と承認を行います。
主な機能
- 01安全性に応じたブランチ分類
- 02マージ済み、古い、リモート削除済みの識別
- 03現在のブランチと保護対象ブランチの保護
- 04未プッシュコミットと worktree の確認
- 05削除候補のプレビューと承認確認
活用シーン
- 01マージ済みローカルブランチの整理
- 02リモート削除済みや長期間更新のないブランチの確認
- 03削除前の未プッシュコミットと worktree の確認
- 04削除対象ブランチのプレビュー
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ gotalab/ skillport --skill git-branch-cleanupインストール後、Claude Code で/git-branch-cleanupを入力して読み込まれたか確認します。
詳細
Git Branch Cleanup
ローカルの Git ブランチを安全に整理、クリーンアップします。マージ状況、古さ、リモート追跡の状態に基づいてブランチを分類し、安全に削除できるよう案内します。
Contents
- クイックスタート
- ワークフロー(ステップ 1~5)
- コマンドリファレンス
- ドライランモード
- 安全チェックリスト
クイックスタート
- ブランチを分析する(ステップ 1)
- 安全レベルごとに分類する(ステップ 2)
- 結果を表示し、どのブランチを削除するかユーザーに尋ねる(ステップ 3)
- 安全ガードを確認する(ステップ 4)
- 確認後に削除を実行する(ステップ 5)
ワークフロー
ステップ 1:ブランチ分析
以下のコマンドで情報を収集します。
# Decide base branch (prefer auto-detect; fallback to main)
BASE_BRANCH="$(
git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@'
)"
[ -n "$BASE_BRANCH" ] || BASE_BRANCH=main
# List all branches with last commit date
git for-each-ref --sort=-committerdate refs/heads/ \
--format='%(refname:short)|%(committerdate:relative)|%(upstream:trackshort)|%(contents:subject)'
# Merged branches (against base)
git branch --merged "$BASE_BRANCH"
# Unmerged branches
git branch --no-merged "$BASE_BRANCH"
# Branches whose upstream is gone (remote deleted)
git branch -vv | grep -F ': gone]' || true
# List worktrees (branches with '+' prefix in git branch -v have worktrees)
git worktree list
# Branches with worktrees ('+' prefix indicates worktree association)
git branch -v | grep '^+' || true
# Branches ahead of upstream (have unpushed commits)
git for-each-ref refs/heads \
--format='%(refname:short) %(upstream:trackshort)' \
| grep '>' || true
ステップ 2:分類
ブランチを安全レベルごとに分類します。
| カテゴリ | 説明 | 安全性 |
|---|---|---|
| マージ済み(安全) | ベースブランチにすでにマージ済み | 安全に削除できます |
| リモートに存在しない | リモートブランチが削除済み | 確認を推奨します |
| 古いブランチ | 30 日以上コミットがない | 確認が必要です |
| ワークツリーあり | ブランチがワークツリーでチェックアウトされている(git branch -v で + 接頭辞が表示される) | 先にワークツリーを削除します |
| 上流より先行 | プッシュされていないコミットがある | ⚠️ 削除しないでください |
| 未マージ | 作業が進行中 | 注意して扱ってください |
注:古いブランチを判定する基準として、30 日は妥当なデフォルト値です。必要に応じてチームのスプリントサイクルに合わせて調整してください(例:2 週間スプリントの場合は 14 日)。
ステップ 3:表示形式
## Branch Analysis Results
### Safe to Delete (Merged)
- feature/login (3 weeks ago) - Add login feature
- fix/typo (2 months ago) - Fix typo in readme
### Remote Deleted
- feature/old-api (1 month ago) - Remote branch no longer exists
### ⚠️ Ahead of Upstream (DO NOT DELETE)
- feature/wip (1 day ago) - Has 3 unpushed commits
### Stale Branches (30+ days)
- experiment/cache (2 months ago) - Unmerged
### Active (Unmerged)
- feature/new-dashboard (2 days ago) - Work in progress
---
Which categories would you like to delete?
1. Merged only (safest)
2. Merged + remote deleted
3. Select individually
ステップ 4:安全ガード
以下のブランチは削除しないでください。
mainmastertrunkdevelopdevelopment- 現在チェックアウトされているブランチ
削除前に必ず確認します。
The following branches will be deleted:
- feature/login
- fix/typo
Continue? (y/N)
ステップ 5:削除の実行
# After confirmation
git branch -d <branch-name> # For merged branches
git branch -D <branch-name> # Force delete (unmerged)
ワークツリーがあるブランチの場合は、先にワークツリーを削除します。
# Check if branch has a worktree
git worktree list | grep "\\[$branch\\]"
# Remove worktree before deleting branch
git worktree remove --force /path/to/worktree
git branch -D <branch-name>
ワークツリーを処理しながら [gone] ブランチを一括削除する場合:
# Process all [gone] branches, handling worktrees automatically
git branch -v | grep '\[gone\]' | sed 's/^[+* ]//' | awk '{print $1}' | while read branch; do
echo "Processing branch: $branch"
# Find and remove worktree if it exists
worktree=$(git worktree list | grep "\\[$branch\\]" | awk '{print $1}')
if [ ! -z "$worktree" ] && [ "$worktree" != "$(git rev-parse --show-toplevel)" ]; then
echo " Removing worktree: $worktree"
git worktree remove --force "$worktree"
fi
# Delete the branch
echo " Deleting branch: $branch"
git branch -D "$branch"
done
コマンドリファレンス
# Bulk delete merged branches (excluding protected branches and current branch)
# Notes:
# - Uses for loop + case for bash/zsh compatibility (avoids `while IFS= read` issues in zsh).
# - Uses case statement for exact-name matching (avoids grep regex edge cases).
# - Always exclude the current branch to prevent accidental self-deletion.
BASE_BRANCH="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')"
[ -n "$BASE_BRANCH" ] || BASE_BRANCH=main
CURRENT_BRANCH="$(git branch --show-current)"
for branch in $(git branch --merged "$BASE_BRANCH" | sed 's/^[* ]*//'); do
case "$branch" in
main|master|trunk|develop|development|"$CURRENT_BRANCH"|"") continue ;;
*) git branch -d "$branch" ;;
esac
done
# Prune remote-tracking references (requires network access)
# Note: This may fail if offline or remote is unreachable.
# If it fails, skip this step - branch analysis still works with cached remote data.
git fetch --prune || echo "Warning: Could not reach remote. Using cached data."
# List oldest branches (30+ days)
git for-each-ref --sort=committerdate refs/heads/ \
--format='%(committerdate:short) %(refname:short)' | head -20
# Worktree commands
git worktree list # List all worktrees
git worktree remove /path/to/worktree # Remove a worktree
git worktree remove --force /path/to/worktree # Force remove (even if dirty)
git worktree prune # Clean up stale worktree refs
ドライランモード
削除を実行せずにプレビューします。
# Preview only
BASE_BRANCH="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')"
[ -n "$BASE_BRANCH" ] || BASE_BRANCH=main
CURRENT_BRANCH="$(git branch --show-current)"
for branch in $(git branch --merged "$BASE_BRANCH" | sed 's/^[* ]*//'); do
case "$branch" in
main|master|trunk|develop|development|"$CURRENT_BRANCH"|"") ;;
*) echo "$branch" ;;
esac
done
ユーザーが「--dry-run」、「preview」、または「just show me」と指定した場合は、ドライランモードを実行します。
安全チェックリスト
削除する前に、以下を確認します。
- 現在のブランチではない
- 保護対象のブランチ(base/main/master/trunk/develop)ではない
- プッシュされていないコミットがない(上流より先行していない)
- (ブランチに関連付けられたワークツリーがある場合)先にワークツリーを削除済み
- ユーザーの確認を得ている
安全性をすばやく確認するコマンド
# Show "ahead/behind" vs upstream for each local branch
git for-each-ref refs/heads \
--format='%(refname:short)|%(upstream:short)|%(upstream:trackshort)|%(committerdate:relative)|%(contents:subject)' \
--sort=-committerdate
# For a specific branch, confirm it's not ahead of upstream (if upstream exists)
# (Empty output => nothing unpushed)
git log --oneline @{u}..HEAD 2>/dev/null || echo "No upstream configured for this branch"
# Check if a branch has an associated worktree
# ('+' prefix in git branch -v output indicates worktree)
git branch -v | grep "^+" | awk '{print $2}'
# Find worktree path for a specific branch
git worktree list | grep "\\[branch-name\\]"
コメント
Markdown 対応