Delete a git clone or worktree — only when it is genuinely safe to do so.
$ git-remove ~/projects/old-feature
Removed: /home/user/projects/old-feature
$ git-remove ~/projects/wip
UNSAFE: (root): branch 'wip' has unpushed commits
UNSAFE: (root): untracked (non-ignored) files present
Skipped: /home/user/projects/wip
The script refuses to delete anything it cannot prove is safe. For the common case — a feature branch you finished and pushed — it gets out of the way instantly.
Before touching anything on disk, git-remove verifies:
| Check | What it catches |
|---|---|
| No uncommitted changes | Staged or unstaged edits to tracked files |
| No untracked files | New files not yet added to git (ignored files are exempt) |
| No stash entries | Work stashed and not yet applied |
| No unpushed commits | Every branch is either fully pushed to its upstream, or all of its commits are already reachable from a remote ref |
| No unpushed tags | Every local tag is present on at least one remote (queried via git ls-remote) |
All checks run on the repo root and recursively on every initialised submodule. A single failure anywhere in the tree blocks the deletion.
Detached HEAD is handled correctly: when HEAD is not on a branch, the script checks whether the current commit (and its ancestors) are reachable from any remote ref.
The checks above cover the most common sources of lost work, but some things are not checked and will be silently destroyed along with the directory:
Local branches pointing to already-pushed commits A branch that has no commits of its own — its tip is identical to the remote — passes the push check cleanly. The branch name and its tracking configuration are lost. You can recreate the branch from the remote, but the script will not warn you that local branch names are about to disappear.
Orphaned / dangling commits
Commits that are no longer reachable from any branch or tag (e.g. the original
commits after an interactive rebase, or the old HEAD after a git reset --hard)
live in the object store and in the reflog but are invisible to normal branch
inspection. These are permanently gone when the directory is deleted.
Repo-local config
Anything in .git/config that is not replicated elsewhere — custom remotes,
per-repo hooks, credential settings — is deleted with the repo.
If any of the above matters to you, inspect the repository manually before
running git-remove.
Runs all safety checks and exits 0 if the repo is safe to remove, 1
otherwise. Useful on its own before deciding what to do manually.
$ git-check-worktree ~/projects/spike
UNSAFE: (root): stash entries present
$ echo $?
1
Checks each path, then deletes those that pass. Linked worktrees are removed
with git worktree remove; full clones and bare repos are deleted with
rm -rf. The current working directory is never a valid target.
| Repo type | Detected by | Deletion method |
|---|---|---|
| Linked worktree | .git is a file |
git worktree remove |
| Normal clone | .git is a directory |
rm -rf |
| Bare repo | HEAD + objects/ at root |
rm -rf (only if no linked worktrees) |
Copy both scripts somewhere on your $PATH:
cp git-check-worktree git-remove ~/.local/bin/
chmod +x ~/.local/bin/git-check-worktree ~/.local/bin/git-removeBecause the scripts are named git-<cmd>, git picks them up automatically:
git remove ~/projects/old-feature
git check-worktree ~/projects/old-featurebash tests/run_tests.shThe suite creates isolated temporary repositories for each scenario and cleans up after itself. No system state is modified.
- Bash 4+
- Git 2.5+ (worktree support)
- Standard Unix tools:
realpath,rm
Linux is the primary target. macOS works with GNU coreutils (brew install coreutils).