CtrlK
BlogDocsLog inGet started
Tessl Logo
SkillPublic

git-worktree-clean

Clean up stale git worktrees with merged branch detection and disk usage report

Quality

69%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./examples/skills/git-worktree-clean/SKILL.md
SKILL.md
Quality
Evals
Security

Git worktree clean

Batch cleanup of stale git worktrees. Safely removes merged branches, reports disk usage, and handles unmerged branches interactively.

Core principle: Auto-clean merged worktrees, interactive review for unmerged, always report what was reclaimed.

Part of: Worktree Lifecycle Suite | /git-worktree | /git-worktree-status | /git-worktree-remove

Process

  1. List All Worktrees: git worktree list
  2. Classify Each: merged vs unmerged vs protected
  3. Calculate Disk Usage: Per-worktree size
  4. Auto Mode: Remove all merged worktrees (safe)
  5. Interactive Mode: Review unmerged worktrees one by one
  6. Database Cleanup Reminder: List DB branches to clean
  7. Report: Summary of actions taken and space reclaimed

Flags

FlagEffect
--dry-runPreview what would be cleaned, no changes
--allInclude unmerged worktrees (interactive confirmation each)
--forceRemove all worktrees without confirmation (dangerous)

Worktree discovery

# Get main branch name
MAIN_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@')
MAIN_BRANCH=${MAIN_BRANCH:-main}

# Protected branches (never auto-clean)
PROTECTED="main master develop staging production"

# List all worktrees (skip main working tree)
git worktree list --porcelain | while read line; do
  # Parse worktree path and branch
  # Skip the main worktree (first entry)
done

Classification

for WORKTREE in $WORKTREES; do
  BRANCH=$(git -C "$WORKTREE" rev-parse --abbrev-ref HEAD)

  # Skip protected
  if echo "$PROTECTED" | grep -qw "$BRANCH"; then
    echo "PROTECTED: $BRANCH (skipped)"
    continue
  fi

  # Check merge status
  if git merge-base --is-ancestor "$BRANCH" "$MAIN_BRANCH" 2>/dev/null; then
    echo "MERGED: $BRANCH → safe to remove"
    MERGED_LIST="$MERGED_LIST $WORKTREE"
  else
    echo "UNMERGED: $BRANCH → requires review"
    UNMERGED_LIST="$UNMERGED_LIST $WORKTREE"
  fi
done

Disk usage calculation

for WORKTREE in $ALL_WORKTREES; do
  # Calculate size excluding symlinked node_modules
  SIZE=$(du -sh --exclude='node_modules' "$WORKTREE" 2>/dev/null | cut -f1)
  # Or on macOS:
  SIZE=$(du -sh -I 'node_modules' "$WORKTREE" 2>/dev/null | cut -f1)
  echo "  $WORKTREE: $SIZE"
done

Dry run mode

# --dry-run: show what would happen without making changes

echo "=== Dry Run ==="
echo ""
echo "Would remove (merged):"
for WT in $MERGED_LIST; do
  echo "  $WT ($BRANCH) - $SIZE"
done
echo ""
echo "Would ask about (unmerged):"
for WT in $UNMERGED_LIST; do
  echo "  $WT ($BRANCH) - $SIZE - last commit: $(git log -1 --format='%s' $BRANCH)"
done
echo ""
echo "Total space to reclaim: $TOTAL_SIZE"
echo ""
echo "Run without --dry-run to execute."

Auto mode (default)

Only removes merged worktrees. Safe by default.

echo "Cleaning merged worktrees..."

for WORKTREE in $MERGED_LIST; do
  BRANCH=$(git -C "$WORKTREE" rev-parse --abbrev-ref HEAD)

  # Remove worktree
  git worktree remove "$WORKTREE"

  # Delete local branch
  git branch -d "$BRANCH" 2>/dev/null

  # Delete remote branch
  git push origin --delete "$BRANCH" 2>/dev/null

  echo "  Removed: $WORKTREE ($BRANCH)"
done

# Report unmerged (not touched)
if [ -n "$UNMERGED_LIST" ]; then
  echo ""
  echo "Unmerged worktrees (kept):"
  for WT in $UNMERGED_LIST; do
    echo "  $WT - use /git-worktree-remove or --all to review"
  done
fi

Interactive Mode (--all)

Reviews unmerged worktrees one by one:

for WORKTREE in $UNMERGED_LIST; do
  BRANCH=$(git -C "$WORKTREE" rev-parse --abbrev-ref HEAD)
  LAST_COMMIT=$(git log -1 --format='%h %s (%cr)' "$BRANCH")
  AHEAD=$(git rev-list --count "$MAIN_BRANCH".."$BRANCH")

  echo ""
  echo "Unmerged: $WORKTREE"
  echo "  Branch: $BRANCH ($AHEAD commits ahead of $MAIN_BRANCH)"
  echo "  Last commit: $LAST_COMMIT"
  echo "  Size: $SIZE"
  echo ""
  echo "  [r]emove  [k]eep  [s]kip remaining"

  # Wait for user decision per worktree
done

Report format

After cleanup:

=== Worktree Cleanup Report ===

Removed (merged):
  .worktrees/feat/auth (feat/auth) - 2.3 MB
  .worktrees/fix/login-bug (fix/login-bug) - 1.1 MB
  .worktrees/chore/deps-update (chore/deps-update) - 0.8 MB

Kept (unmerged):
  .worktrees/feat/experimental (feat/experimental) - 4.2 MB
    Last commit: a1b2c3d "WIP: new auth flow" (3 days ago)

Kept (protected):
  .worktrees/develop (develop)

Space reclaimed: 4.2 MB
Worktrees remaining: 2
References pruned: yes

DB branches to clean:
  neonctl branches delete feat-auth
  neonctl branches delete fix-login-bug
  neonctl branches delete chore-deps-update

Dry run report:

=== Dry Run - No Changes Made ===

Would remove (3 merged):
  .worktrees/feat/auth - 2.3 MB
  .worktrees/fix/login-bug - 1.1 MB
  .worktrees/chore/deps-update - 0.8 MB

Would keep (1 unmerged):
  .worktrees/feat/experimental - 4.2 MB

Would keep (1 protected):
  .worktrees/develop

Potential space savings: 4.2 MB

Quick reference

SituationAction
Default (no flags)Remove merged worktrees only
--dry-runPreview without changes
--allMerged (auto) + unmerged (interactive)
--forceRemove everything except protected
Protected branchAlways kept
Merged branchAuto-removed
Unmerged branchKept (default) or interactive (--all)
DB branches detectedReminder with exact commands

Common mistakes

Running --force without --dry-run first

  • Always preview with --dry-run before force-cleaning

Forgetting DB branch cleanup

  • Worktree cleanup doesn't auto-delete DB branches. Follow the reminder commands.

Not running cleanup regularly

  • Stale worktrees accumulate disk space. Run /git-worktree-clean --dry-run weekly.

Usage

/git-worktree-clean
/git-worktree-clean --dry-run
/git-worktree-clean --all

Flags: $ARGUMENTS

Repository

FlorianBruniaux/claude-code-ultimate-guide

Path

examples/skills/git-worktree-clean/SKILL.md

Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.