# Git Worktree Prune

> Safely prune stale git worktrees and local branches left over from past sessions, deleting only those with no unique work so no commit is ever lost. Use when a repo has accumulated worktrees and branches over many sessions and needs cleanup. Triggers include "prune worktrees", "delete stale branches", "clean up git worktrees/branches", "remove old worktrees", "which branches are safe to delete".

- Skill: `zacheryglass/git-worktree-prune` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add zacheryglass/git-worktree-prune`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zacheryglass/git-worktree-prune/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: zacheryglass (https://skillmd.com/u/zacheryglass)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zacheryglass/git-worktree-prune

---


# Git Worktree & Branch Prune

Remove stale worktrees and local branches from old sessions **without ever losing a commit**.

## Safety invariant

- A **branch** is deleted only when every commit on it is reachable from some *other* surviving ref (another local branch, a remote-tracking branch `origin/*`, or a tag). Branches with unique commits are kept.
- A **worktree** is removed only when it is **clean** (no uncommitted or untracked changes). The branch it held is preserved.
- The **primary worktree**, the **current branch**, and `main`/`master` are always kept.

## Usage

Always dry-run first (the default — it changes nothing), review the plan, then apply:

```bash
python scripts/prune_git.py --repo <path>            # dry-run: prints KEEP/REMOVE/DELETE plan
python scripts/prune_git.py --repo <path> --apply    # execute after reviewing the dry-run
```

Flags:
- `--fetch` — run `git fetch --all --prune` first so branches already merged/pushed to a remote are recognized as deletable. Without it the tool is more *conservative* (stale remotes only ever cause it to keep more, never lose work).
- `--protect BRANCH` — always keep this branch (repeatable). Use for branches with no unique commits that you still want to keep (see below).
- `--repo PATH` — a path inside the target repo (default: cwd).

## Review the DELETE list before `--apply`

The "no unique commits" rule is about *commits*, not intent. A branch can be flagged **DELETE** while still being meaningful — most commonly a **feature branch that a descendant now subsumes** (e.g., you branched `research/x` off `feat/y`, so `feat/y`'s commits now also live on `research/x`). No commit is lost if it's deleted, but the branch *name* and its PR track are. Keep such a branch with `--protect <name>`.

Every removal is printed with its reason; a branch shown as `KEEP -- N unique commit(s)` holds work found nowhere else and is never touched.

## Notes

- Never deletes remote-tracking refs, tags, or the reflog — only local branches and worktree checkouts.
- Removing a worktree that holds a branch (even a protected one like `main`) frees the branch without deleting it; you can then check it out in the primary worktree.
- Worktrees whose directory is already gone are cleaned via `git worktree prune`.
- On Windows, run under Git Bash / a UTF-8 console (`PYTHONIOENCODING=utf-8`) if paths contain non-ASCII characters.

