|
| 1 | +--- |
| 2 | +description: Clean up old and defunct branches that are no longer needed |
| 3 | +argument-hint: [--dry-run] [--merged-only] [--remote] |
| 4 | +--- |
| 5 | + |
| 6 | +## Name |
| 7 | +git:branch-cleanup |
| 8 | + |
| 9 | +## Synopsis |
| 10 | +``` |
| 11 | +/git:branch-cleanup [--dry-run] [--merged-only] [--remote] |
| 12 | +``` |
| 13 | + |
| 14 | +## Description |
| 15 | +The `git:branch-cleanup` command identifies and removes old, defunct, or merged branches from your local repository (and optionally from remote). It helps maintain a clean repository by removing branches that are no longer needed, such as: |
| 16 | +- Branches that have been merged into the main branch |
| 17 | +- Branches that no longer exist on the remote |
| 18 | +- Stale feature branches from completed work |
| 19 | + |
| 20 | +The command performs safety checks to prevent deletion of: |
| 21 | +- The current branch |
| 22 | +- Protected branches (main, master, develop, etc.) |
| 23 | +- Branches with unmerged commits (unless explicitly overridden) |
| 24 | + |
| 25 | +The spec sections is inspired by https://man7.org/linux/man-pages/man7/man-pages.7.html#top_of_page |
| 26 | + |
| 27 | +## Implementation |
| 28 | +The command should follow these steps: |
| 29 | + |
| 30 | +1. **Identify Main Branch** |
| 31 | + - Detect the primary branch (main, master, etc.) |
| 32 | + - Use `git symbolic-ref refs/remotes/origin/HEAD` or `git branch -r` to determine |
| 33 | + |
| 34 | +2. **Gather Branch Information** |
| 35 | + - List all local branches: `git branch` |
| 36 | + - Get current branch: `git branch --show-current` |
| 37 | + - Identify merged branches: `git branch --merged <main-branch>` |
| 38 | + - Check remote tracking: `git branch -vv` |
| 39 | + - Find remote-deleted branches: `git remote prune origin --dry-run` |
| 40 | + |
| 41 | +3. **Categorize Branches** |
| 42 | + - **Merged branches**: Fully merged into main branch |
| 43 | + - **Gone branches**: Remote tracking branch no longer exists |
| 44 | + - **Stale branches**: Last commit older than threshold (e.g., 3 months) |
| 45 | + - **Protected branches**: main, master, develop, release/*, hotfix/* |
| 46 | + |
| 47 | +4. **Present Analysis to User** |
| 48 | + - Show categorized list of branches with: |
| 49 | + - Branch name |
| 50 | + - Last commit date |
| 51 | + - Merge status |
| 52 | + - Remote tracking status |
| 53 | + - Number of commits ahead/behind |
| 54 | + - Recommend branches safe to delete |
| 55 | + |
| 56 | +5. **Confirm Deletion** |
| 57 | + - Ask user to confirm which branches to delete |
| 58 | + - Present options: all merged, all gone, specific branches, or custom selection |
| 59 | + - If `--dry-run` flag is present, only show what would be deleted |
| 60 | + |
| 61 | +6. **Delete Branches** |
| 62 | + - Local deletion: `git branch -d <branch>` (merged) or `git branch -D <branch>` (force) |
| 63 | + - Remote deletion (if `--remote` flag): `git push origin --delete <branch>` |
| 64 | + - Prune remote references: `git remote prune origin` |
| 65 | + |
| 66 | +7. **Report Results** |
| 67 | + - List deleted branches |
| 68 | + - Show any errors or branches that couldn't be deleted |
| 69 | + - Provide summary statistics |
| 70 | + |
| 71 | +Implementation logic: |
| 72 | +```bash |
| 73 | +# Determine main branch |
| 74 | +main_branch=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') |
| 75 | +if [ -z "$main_branch" ]; then |
| 76 | + main_branch="main" # fallback |
| 77 | +fi |
| 78 | + |
| 79 | +# Get current branch |
| 80 | +current_branch=$(git branch --show-current) |
| 81 | + |
| 82 | +# Find merged branches |
| 83 | +git branch --merged "$main_branch" | grep -v "^\*" | grep -v "$main_branch" |
| 84 | + |
| 85 | +# Find branches with deleted remotes ("gone") |
| 86 | +git branch -vv | grep ': gone]' | awk '{print $1}' |
| 87 | + |
| 88 | +# Find stale branches (older than 3 months) |
| 89 | +git for-each-ref --sort=-committerdate --format='%(refname:short)|%(committerdate:iso)|%(upstream:track)' refs/heads/ |
| 90 | + |
| 91 | +# Delete local branch (merged) |
| 92 | +git branch -d <branch-name> |
| 93 | + |
| 94 | +# Delete local branch (force) |
| 95 | +git branch -D <branch-name> |
| 96 | + |
| 97 | +# Delete remote branch |
| 98 | +git push origin --delete <branch-name> |
| 99 | + |
| 100 | +# Prune remote references |
| 101 | +git remote prune origin |
| 102 | +``` |
| 103 | + |
| 104 | +## Return Value |
| 105 | +- **Claude agent text**: Analysis and results including: |
| 106 | + - List of branches categorized by status (merged, gone, stale) |
| 107 | + - Recommendation for which branches are safe to delete |
| 108 | + - Confirmation prompt for user approval |
| 109 | + - Summary of deleted branches and any errors |
| 110 | + - Statistics (e.g., "Deleted 5 branches, freed X MB") |
| 111 | + |
| 112 | +## Examples |
| 113 | + |
| 114 | +1. **Basic usage (interactive)**: |
| 115 | + ``` |
| 116 | + /git:branch-cleanup |
| 117 | + ``` |
| 118 | + Output: |
| 119 | + ``` |
| 120 | + Analyzing branches in repository... |
| 121 | +
|
| 122 | + Main branch: main |
| 123 | + Current branch: feature/new-api |
| 124 | +
|
| 125 | + === Merged Branches (safe to delete) === |
| 126 | + feature/bug-fix-123 Merged 2 weeks ago |
| 127 | + feature/update-deps Merged 1 month ago |
| 128 | +
|
| 129 | + === Gone Branches (remote deleted) === |
| 130 | + feature/old-feature Remote: gone |
| 131 | + hotfix/urgent-fix Remote: gone |
| 132 | +
|
| 133 | + === Stale Branches (no activity > 3 months) === |
| 134 | + experiment/prototype Last commit: 4 months ago, not merged |
| 135 | +
|
| 136 | + === Protected Branches (will not delete) === |
| 137 | + main |
| 138 | + develop |
| 139 | +
|
| 140 | + Recommendations: |
| 141 | + - Safe to delete: feature/bug-fix-123, feature/update-deps (merged) |
| 142 | + - Safe to delete: feature/old-feature, hotfix/urgent-fix (remote gone) |
| 143 | + - Review needed: experiment/prototype (unmerged, stale) |
| 144 | +
|
| 145 | + What would you like to delete? |
| 146 | + ``` |
| 147 | + |
| 148 | +2. **Dry run (preview only)**: |
| 149 | + ``` |
| 150 | + /git:branch-cleanup --dry-run |
| 151 | + ``` |
| 152 | + Output: |
| 153 | + ``` |
| 154 | + [DRY RUN MODE - No changes will be made] |
| 155 | +
|
| 156 | + Would delete the following merged branches: |
| 157 | + - feature/bug-fix-123 |
| 158 | + - feature/update-deps |
| 159 | +
|
| 160 | + Would delete the following gone branches: |
| 161 | + - feature/old-feature |
| 162 | + - hotfix/urgent-fix |
| 163 | +
|
| 164 | + Total: 4 branches would be deleted |
| 165 | + ``` |
| 166 | + |
| 167 | +3. **Merged branches only**: |
| 168 | + ``` |
| 169 | + /git:branch-cleanup --merged-only |
| 170 | + ``` |
| 171 | + Output: |
| 172 | + ``` |
| 173 | + Analyzing merged branches... |
| 174 | +
|
| 175 | + Found 3 merged branches: |
| 176 | + - feature/bug-fix-123 |
| 177 | + - feature/update-deps |
| 178 | + - feature/ui-improvements |
| 179 | +
|
| 180 | + Delete these branches? (y/n) |
| 181 | + ``` |
| 182 | + |
| 183 | +4. **Including remote cleanup**: |
| 184 | + ``` |
| 185 | + /git:branch-cleanup --remote |
| 186 | + ``` |
| 187 | + Output: |
| 188 | + ``` |
| 189 | + Deleting local and remote branches... |
| 190 | +
|
| 191 | + ✓ Deleted local: feature/bug-fix-123 |
| 192 | + ✓ Deleted remote: origin/feature/bug-fix-123 |
| 193 | + ✓ Deleted local: feature/update-deps |
| 194 | + ✓ Deleted remote: origin/feature/update-deps |
| 195 | +
|
| 196 | + Summary: Deleted 2 branches locally and remotely |
| 197 | + ``` |
| 198 | + |
| 199 | +## Arguments |
| 200 | +- `--dry-run`: Preview which branches would be deleted without actually deleting them |
| 201 | +- `--merged-only`: Only consider branches that have been fully merged into the main branch |
| 202 | +- `--remote`: Also delete branches from the remote repository (requires push permissions) |
| 203 | +- `--force`: Force delete branches even if they have unmerged commits (use with caution) |
| 204 | +- `--older-than=<days>`: Only consider branches with no commits in the last N days (default: 90) |
| 205 | + |
| 206 | +## Safety Considerations |
| 207 | +- **Never delete**: Current branch, main, master, develop, or release/* branches |
| 208 | +- **Require confirmation**: Always ask user before deleting branches |
| 209 | +- **Preserve unmerged work**: By default, only delete merged branches unless `--force` is used |
| 210 | +- **Backup suggestion**: Recommend creating a backup of unmerged branches before deletion |
| 211 | +- **Remote deletion**: Only delete remote branches if user explicitly requests with `--remote` flag |
0 commit comments