| name | prune-worktrees |
| description | Clean up worktrees for merged branches. Triggers on 'prune worktrees', 'cleanup worktrees', 'remove merged worktrees'. |
| version | 0.2.8 |
Prune Worktrees
Clean up worktrees whose branches have been merged on GitLab or GitHub.
On Skill Load
Run the cleanup check automatically:
REMOTE_URL=$(git remote get-url origin)
if [[ "$REMOTE_URL" == *"gitlab"* ]]; then
CLI="glab"
elif [[ "$REMOTE_URL" == *"github"* ]]; then
CLI="gh"
else
echo "Unknown remote type: $REMOTE_URL"
exit 1
fi
git worktree list
Detection Logic
Use git worktree list to find all worktrees regardless of location. Skip the main worktree (first entry).
For each non-main worktree:
- Get the path and branch from
git worktree list
- Check if a merged MR/PR exists for that branch:
- GitLab:
glab mr list --merged --source-branch <branch>
- GitHub:
gh pr list --state merged --head <branch>
- If merged, mark for cleanup
Also check the current worktree - if we're on a branch that's been merged, flag it.
Output Format
Present findings to user:
Worktree Cleanup Check
======================
Merged (safe to remove):
/path/to/feature-123 (branch: feature-123, MR !45 merged)
/path/to/fix-bug (branch: fix-bug, PR #67 merged)
Not merged (keep):
/path/to/wip-stuff (branch: wip-stuff, no merged MR/PR)
Dirty (has uncommitted changes):
/path/to/dirty-one (branch: dirty-one, has uncommitted changes)
Cleanup Commands
After user confirms, remove merged worktrees:
git worktree remove <path>
git worktree prune
git push origin --delete <branch>
Safety Rules
Script
#!/bin/bash
set -euo pipefail
REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")
if [[ "$REMOTE_URL" == *"gitlab"* ]]; then
CLI="glab"
elif [[ "$REMOTE_URL" == *"github"* ]]; then
CLI="gh"
else
echo "Error: Cannot detect GitLab or GitHub from remote: $REMOTE_URL"
exit 1
fi
echo "Checking worktrees for merged branches..."
echo
MERGED=()
UNMERGED=()
DIRTY=()
FIRST=true
git worktree list | while read -r wt_path wt_sha wt_branch_raw; do
if $FIRST; then
FIRST=false
continue
fi
branch="${wt_branch_raw#[}"
branch="${branch%]}"
if [[ "$branch" == "(detached" || -z "$branch" ]]; then
UNMERGED+=("$wt_path (detached HEAD)")
continue
fi
if [[ -n $(git -C "$wt_path" status --porcelain 2>/dev/null) ]]; then
DIRTY+=("$wt_path ($branch) - has uncommitted changes")
continue
fi
if [[ "$CLI" == "glab" ]]; then
merged=$($CLI mr list --merged --source-branch "$branch" 2>/dev/null | head -1)
else
merged=$($CLI pr list --state merged --head "$branch" 2>/dev/null | head -1)
fi
if [[ -n "$merged" ]]; then
MERGED+=("$wt_path ($branch) - $merged")
else
UNMERGED+=("$wt_path ($branch)")
fi
done
if [[ ${#MERGED[@]} -gt 0 ]]; then
echo "MERGED (safe to remove):"
for item in "${MERGED[@]}"; do
echo " $item"
done
echo
fi
if [[ ${#DIRTY[@]} -gt 0 ]]; then
echo "DIRTY (has uncommitted changes - review first):"
for item in "${DIRTY[@]}"; do
echo " $item"
done
echo
fi
if [[ ${#UNMERGED[@]} -gt 0 ]]; then
echo "NOT MERGED (keep):"
for item in "${UNMERGED[@]}"; do
echo " $item"
done
echo
fi
if [[ ${#MERGED[@]} -eq 0 ]]; then
echo "No merged worktrees to clean up."
fi
Run this script, then ask the user which worktrees to remove.