0
0
# Install this skill:
npx skills add Anshin-Health-Solutions/superpai --skill "clean-gone"

Install specific skill from multi-skill repository

# Description

Safely clean up local git branches whose remote tracking reference has been deleted (marked as [gone]). Handles worktree removal before branch deletion, supports a dry-run mode for previewing changes, and integrates with the git-worktrees skill.

# SKILL.md


name: clean-gone
description: Safely clean up local git branches whose remote tracking reference has been deleted (marked as [gone]). Handles worktree removal before branch deletion, supports a dry-run mode for previewing changes, and integrates with the git-worktrees skill.
triggers:
- /clean-gone
- "clean up gone branches"
- "delete merged branches"
- "prune stale branches"
- "remove gone tracking"


Clean Gone Branches

Purpose

When pull requests are merged and source branches are deleted on the remote, local branches accumulate with [gone] tracking references. Over time this creates dozens of stale branches that clutter git branch -v, make tab completion noisy, and can cause confusion about what is still active. This skill identifies all such branches, checks for associated worktrees, removes worktrees safely, then deletes the branches.


Phase 1: Update Remote State

Before identifying [gone] branches, synchronize remote state:

# Fetch all remotes and prune deleted remote-tracking references
git fetch --prune --all

# Confirm fetch succeeded and pruned refs are noted in output
# Example output: "[pruned] origin/feat/old-feature"

Never run branch cleanup without fetching first. The [gone] status is only visible after the remote tracking refs are pruned.


Phase 2: Identify [gone] Branches

List all local branches whose upstream tracking branch has been deleted:

# List branches with their upstream tracking status
git branch -vv

Sample output:

  feat/auth-pkce        a1b2c3d [origin/feat/auth-pkce: gone] add PKCE flow
  feat/billing-refactor 9f8e7d6 [origin/feat/billing-refactor: gone] refactor billing
* main                  c4d5e6f [origin/main] merge auth changes
  dev                   3a2b1c0 [origin/dev] latest dev build

Extract only the [gone] branches:

git branch -vv | grep ': gone]' | awk '{print $1}'

Store the list for iteration:

GONE_BRANCHES=$(git branch -vv | grep ': gone]' | awk '{print $1}')
echo "Branches marked [gone]:"
echo "$GONE_BRANCHES"

Phase 3: Safety Checks

Before deleting any branch, run these safety checks for each candidate:

Check 1: Not the Current Branch

CURRENT=$(git branch --show-current)
for branch in $GONE_BRANCHES; do
  if [ "$branch" = "$CURRENT" ]; then
    echo "SKIP: $branch is the current branch — switch away first"
  fi
done

Check 2: Fully Merged Into Main or Dev

for branch in $GONE_BRANCHES; do
  if git merge-base --is-ancestor "$branch" main; then
    echo "SAFE: $branch is merged into main"
  elif git merge-base --is-ancestor "$branch" dev; then
    echo "SAFE: $branch is merged into dev"
  else
    echo "WARNING: $branch has commits not in main or dev — review before deleting"
    git log main.."$branch" --oneline
  fi
done

If a branch has unmerged commits, report it and skip it. Do not delete unmerged branches without explicit user confirmation.

Check 3: Associated Worktrees

# List all worktrees
git worktree list

Sample output:

C:/projects/myapp                  c4d5e6f [main]
C:/projects/myapp-feat-auth-pkce   a1b2c3d [feat/auth-pkce]
C:/projects/myapp-billing          9f8e7d6 [feat/billing-refactor]

Identify worktrees that are checked out on a [gone] branch:

git worktree list --porcelain | grep -A2 "branch refs/heads/feat/auth-pkce"

A worktree must be removed before its branch can be deleted. Git will refuse to delete a branch that has an active worktree.


Phase 4: Dry-Run Mode

Always present what will happen before taking action. Dry-run is the default mode.

echo "=== DRY RUN: No changes will be made ==="
echo ""

for branch in $GONE_BRANCHES; do
  echo "Would process: $branch"

  # Check for worktree
  WORKTREE_PATH=$(git worktree list | grep "\[$branch\]" | awk '{print $1}')
  if [ -n "$WORKTREE_PATH" ]; then
    echo "  -> Would remove worktree at: $WORKTREE_PATH"
  fi

  echo "  -> Would delete branch: $branch"
done

echo ""
echo "Run with --execute to apply these changes."

Only proceed to Phase 5 when the user explicitly confirms with --execute or equivalent approval.


Phase 5: Worktree Removal

For each branch that has an associated worktree:

# Get the worktree path for a specific branch
WORKTREE_PATH=$(git worktree list | grep "\[feat/auth-pkce\]" | awk '{print $1}')

# Remove the worktree
git worktree remove "$WORKTREE_PATH"

# If the worktree has uncommitted changes, use --force only after user confirmation
git worktree remove --force "$WORKTREE_PATH"

After removal, verify:

git worktree list
# The removed worktree should no longer appear

If git worktree remove fails because the directory no longer exists on disk, use:

git worktree prune

This cleans up stale worktree metadata without requiring the directory to exist.


Phase 6: Branch Deletion

After worktrees are removed, delete the branches:

for branch in $GONE_BRANCHES; do
  # Skip current branch
  if [ "$branch" = "$(git branch --show-current)" ]; then
    echo "SKIPPED (current): $branch"
    continue
  fi

  # Delete merged branch (safe delete — refuses to delete unmerged)
  if git branch -d "$branch" 2>/dev/null; then
    echo "DELETED: $branch"
  else
    echo "SKIPPED (unmerged commits): $branch — use -D to force delete if intended"
  fi
done

Use -d (lowercase), not -D (uppercase). The lowercase form refuses to delete branches with unmerged commits, which prevents data loss. Only escalate to -D when the user explicitly instructs it and you have confirmed the branch's commits are irrelevant.


Phase 7: Verification

After all deletions:

# Confirm no [gone] branches remain
git branch -vv | grep ': gone]'
# Should produce no output

# Show current clean branch list
git branch -v

# Verify worktrees are clean
git worktree list

Full Executable Script

#!/usr/bin/env bash
# clean-gone.sh — Remove local branches with [gone] remote tracking refs
# Usage: ./clean-gone.sh [--execute]

set -euo pipefail

EXECUTE=false
if [ "${1:-}" = "--execute" ]; then
  EXECUTE=true
fi

echo "Fetching and pruning remote refs..."
git fetch --prune --all

GONE_BRANCHES=$(git branch -vv | grep ': gone]' | awk '{print $1}')
CURRENT=$(git branch --show-current)

if [ -z "$GONE_BRANCHES" ]; then
  echo "No [gone] branches found. Nothing to clean."
  exit 0
fi

echo ""
echo "Found [gone] branches:"
echo "$GONE_BRANCHES" | sed 's/^/  /'

if [ "$EXECUTE" = false ]; then
  echo ""
  echo "DRY RUN complete. Run with --execute to apply changes."
  exit 0
fi

echo ""
echo "Removing worktrees and branches..."

for branch in $GONE_BRANCHES; do
  if [ "$branch" = "$CURRENT" ]; then
    echo "SKIP (current branch): $branch"
    continue
  fi

  WORKTREE_PATH=$(git worktree list | grep "\[$branch\]" | awk '{print $1}' || true)
  if [ -n "$WORKTREE_PATH" ]; then
    echo "Removing worktree: $WORKTREE_PATH"
    git worktree remove "$WORKTREE_PATH" || git worktree prune
  fi

  if git branch -d "$branch" 2>/dev/null; then
    echo "DELETED: $branch"
  else
    echo "SKIPPED (unmerged): $branch"
  fi
done

echo ""
echo "Done. Remaining branches:"
git branch -v

Integration with git-worktrees Skill

When the git-worktrees skill is active, call /clean-gone as part of the worktree teardown flow:

  1. User merges PR on GitHub
  2. Run /clean-gone --dry-run to preview stale state
  3. User approves cleanup
  4. Run /clean-gone --execute to remove worktrees and branches
  5. git-worktrees skill updates its internal worktree registry

This keeps the worktree registry synchronized with actual disk and git state.


Output Format

CLEAN-GONE RESULT

Mode: DRY RUN | EXECUTED
Fetched: origin (pruned N refs)

Branches found [gone]: N
  - feat/branch-one (worktree at /path/to/worktree)
  - feat/branch-two (no worktree)
  - feat/branch-three (SKIPPED — unmerged commits)

Actions taken:
  - Removed worktree: /path/to/worktree
  - Deleted branch: feat/branch-one
  - Deleted branch: feat/branch-two
  - Skipped branch: feat/branch-three

Remaining local branches: N
No [gone] branches remain.

Common Errors and Fixes

Error Cause Fix
error: Cannot delete branch 'X' checked out at 'Y' Worktree still active Remove worktree first with git worktree remove
error: The branch 'X' is not fully merged Unmerged commits Review commits, then use git branch -D only if safe
fatal: 'X' is not a valid branch name Branch name has special chars Quote the branch name in the command
Worktree path no longer exists on disk Directory was manually deleted Run git worktree prune to clean metadata

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.