| name | cleanup-stashes |
| description | Review and selectively drop git stashes. Lists all stashes with branch, age, and file
summary. Flags stashes whose branch no longer exists (orphaned work) or has been merged
to main (likely superseded), and stashes older than 14 days (likely forgotten).
Generates a drop script for user approval — never drops stashes directly.
|
Created: 2026-02-23-00-00
Last Updated: 2026-02-23-00-00
Git Stash Cleanup
Review accumulated stashes, surface orphaned or stale ones, and generate a drop script
for approval. Never drops stashes directly — always generates a script for the user to run.
Usage
/cleanup-stashes
/cleanup-stashes --dry-run
/cleanup-stashes --show <N>
Step 1: List All Stashes
git stash list --format="%gd | %gs | %ci"
If the output is empty, report "No stashes found." and stop.
For each stash, collect:
- Index:
stash@{N}
- Branch it was created on (parsed from the stash message, e.g.
WIP on feat-auth: abc1234 message)
- Date created
- Short message
Step 2: Analyze Each Stash
For each stash, run:
git stash show stash@{N} --stat
git log -1 --format="%cr" stash@{N}
git show-ref --verify --quiet refs/heads/<branch> && echo "exists" || echo "gone"
git ls-remote --heads origin <branch> | grep -q . && echo "on remote" || echo "not on remote"
git branch --merged main | grep -q "^ <branch>$" && echo "merged" || echo "not merged"
Step 3: Categorize
Assign each stash to exactly one category (first match wins):
| Category | Condition | Risk |
|---|
| Orphaned | Branch gone locally AND not on remote | High — work may be lost if dropped |
| Superseded | Branch merged to main | Medium — likely safe, but show stat |
| Stale | Age > 14 days (branch still exists) | Medium — probably forgotten |
| Recent | Age ≤ 14 days | Low — likely intentional WIP |
Step 4: Present Analysis
Print a summary grouped by category. For each stash show: index, branch, age, and the
--stat summary (files changed, insertions, deletions).
Example output:
📦 Stash Analysis — 5 stashes found
🔴 ORPHANED (branch no longer exists) — review carefully before dropping
stash@{2} feat-old-experiment 43 days ago
3 files changed, 89 insertions(+)
"WIP on feat-old-experiment: abc1234 add initial draft"
🟡 SUPERSEDED (branch merged to main)
stash@{4} feat-auth 22 days ago
1 file changed, 4 insertions(+), 2 deletions(-)
"WIP on feat-auth: def5678 tweak error message"
🟡 STALE (branch exists but stash is >14 days old)
stash@{1} feat-ui 18 days ago
5 files changed, 201 insertions(+)
"WIP on feat-ui: ghi9012 modal work in progress"
🟢 RECENT (likely intentional WIP — keeping)
stash@{0} feat-payments 2 days ago
2 files changed, 34 insertions(+)
"WIP on feat-payments: jkl3456 stripe integration"
stash@{3} feat-payments 5 days ago
1 file changed, 8 insertions(+)
"WIP on feat-payments: jkl3456 add webhook handler"
Tip: run /cleanup-stashes --show <N> to see the full diff for any stash before deciding.
If --dry-run was passed, stop here.
Step 5: Generate Drop Script
Group only the Orphaned, Superseded, and Stale stashes into the script.
Recent stashes are never included unless --force is passed.
Important: git stash drop indices shift after each drop. Always drop in
descending index order so earlier indices remain valid.
#!/bin/bash
echo "Stashes to be dropped:"
echo ""
echo "Orphaned stashes (branch gone):"
git stash drop stash@{2}
echo ""
echo "Superseded stashes (branch merged):"
git stash drop stash@{4}
echo ""
echo "Stale stashes (>14 days old):"
git stash drop stash@{1}
echo ""
echo "Done. Dropped 3 stashes."
Present the script and remind the user:
- Dropped stashes cannot be recovered
- Run
--show <N> to inspect any stash before running the script
- Recent stashes are not included
Safety Rules
NEVER run git stash drop directly — this skill only generates scripts for user approval.
Always:
- Sort drop commands descending by index (highest N first)
- Show the stat summary for every stash suggested for dropping
- Leave Recent stashes out of the script entirely
- Warn clearly on Orphaned stashes (work may not exist anywhere else)
Never:
- Drop stashes with no stash list output to verify against
- Assume a stash is safe to drop based on age alone
- Include stash@{0} in the script if it was created recently