Delete local and remote Git tags with dry-run, summary, and protection.
git-delete-tags removes one or more tags from a repository — locally, on a remote, or both. You can name specific tags, pass all to target every tag, and protect selected names from deletion.
Use it when cleaning up stale release tags, resetting tag namespaces before a fresh release cycle, or removing tags that should never have been pushed.
With Homebrew:
brew tap the-lupaxa-project/tap
brew trust the-lupaxa-project/tap
brew install git-delete-tagsOr run the script from a clone: ./src/git-delete-tags --help.
./src/git-delete-tags all --summary # plan only — no changes
./src/git-delete-tags -n v1.0.0 # dry-run (commands simulated)
./src/git-delete-tags v1.0.0 # delete one tag (local + remote)
./src/git-delete-tags all -y # delete all tags (non-interactive)This is destructive. Prefer --summary or -n first.
With no mode flags, the script will:
- Resolve requested tags (explicit names or
all) - Drop protected tags (
-T/--protect-tag) - Delete matching tags on the remote (one
git push --deleteper tag) - Delete matching tags locally (one
git tag -dper tag)
Remote tag names are discovered via git ls-remote --tags.
| Flag | Purpose |
|---|---|
-r, --remote NAME |
Remote to operate on (default: origin) |
--local-only |
Delete only local tags (no remote operations) |
--remote-only |
Delete only remote tags (keep local tags) |
-T, --protect-tag TAG |
Protect a specific tag from deletion (repeatable) |
-y, --yes |
Skip the interactive DELETE confirmation |
-n, --dry-run |
Simulate commands without changing anything |
-S, --summary |
Print a detailed plan based on all options and exit |
-V, --version |
Print version and exit |
./src/git-delete-tags --helpPreview what deleting all tags would do:
./src/git-delete-tags all --summaryDry-run a single tag delete:
./src/git-delete-tags v2.0.0 --dry-runDelete all tags except protected ones:
./src/git-delete-tags all -T v1.0.0 -T latest --yesRemove tags from the remote only:
./src/git-delete-tags all --remote-only --yes--dry-runprints the action plan and simulates commands without asking forDELETE.- Real runs require typing
DELETEunless you pass-y/--yes. --summaryresolves tags and prints the plan only — no deletes are run.- Protection is applied before existence checks, so a missing explicit tag that is also protected (for example,
no-such -T no-such) is skipped and may exit 0. - Explicit tag names: the script fails if a named tag is missing from every place the selected mode would touch (default: local and/or remote;
--local-only: local;--remote-only: remote). - With
all, only tags that exist for the selected mode are deleted; the script may exit 0 with nothing to delete. - Remote tag discovery uses
git ls-remote --tags; a missing or unreachable remote fails before any deletes. - Remote deletes run before local deletes; a remote failure aborts before local tags are touched.