GitDeleting Tags

Deleting Tags

Deleting a tag removes the named reference — the commit itself is unaffected. Tags occasionally need to be deleted when you tagged the wrong commit, need to correct a version number, or are cleaning up experimental markers. Deleting a remote tag requires an extra step and can affect every developer who has already cloned the repository.

Delete a local tag

Delete one local tag

Bash
git tag -d v1.0.0
# Deleted tag 'v1.0.0' (was 3f8a2c9)

# Verify it is gone
git tag
# (v1.0.0 no longer listed)

# The underlying commit is unchanged
git log --oneline -1
# 3f8a2c9 (HEAD -> main) Final tweaks before release
Deleting a tag never deletes commits
A tag is just a pointer. Removing it does not remove the commit from the repository. The commit is still reachable through branches or through its hash directly.
Delete multiple local tags at once

Delete several tags in one command

Bash
# Delete two tags at once
git tag -d v1.0.0 v1.0.1
# Deleted tag 'v1.0.0' (was 3f8a2c9)
# Deleted tag 'v1.0.1' (was 7e4f1a2)

# Delete all tags matching a pattern (using shell expansion)
git tag -l "v0.*" | xargs git tag -d
# Deleted tag 'v0.1.0' (was a1b2c3d)
# Deleted tag 'v0.2.0' (was e4f5a6b)
# Deleted tag 'v0.3.0' (was c7d8e9f)
Delete a remote tag
Deleting a remote tag affects all clones
When you delete a tag from the remote, any developer who has already fetched that tag will still have it locally. If they push it again, the tag will reappear on the remote. Coordinate with your team before deleting shared tags — especially release tags.

Delete a tag on the remote (modern syntax)

Bash
# Modern Git (2.8+):
git push origin --delete v1.0.0
# To github.com:user/repo.git
#  - [deleted]         v1.0.0

Delete a remote tag (older syntax — still works)

Bash
# Older syntax: push an empty reference to the tag
git push origin :refs/tags/v1.0.0
# To github.com:user/repo.git
#  - [deleted]         v1.0.0

Delete local AND remote tag together

Bash
# Step 1: delete locally
git tag -d v1.0.0
# Deleted tag 'v1.0.0' (was 3f8a2c9)

# Step 2: delete from remote
git push origin --delete v1.0.0
# To github.com:user/repo.git
#  - [deleted]         v1.0.0
Delete multiple remote tags at once

Batch delete remote tags

Bash
# Delete two specific remote tags
git push origin --delete v1.0.0 v1.0.1

# Delete all remote tags matching a pattern:
# 1. Get the list of matching local tags
git tag -l "v0.*"
# v0.1.0
# v0.2.0
# v0.3.0

# 2. Delete them from the remote
git tag -l "v0.*" | xargs git push origin --delete
# To github.com:user/repo.git
#  - [deleted]         v0.1.0
#  - [deleted]         v0.2.0
#  - [deleted]         v0.3.0
Re-tagging: move a tag to a different commit

If you tagged the wrong commit and need to move the tag to the correct one, use the -f (force) flag. Without it, Git refuses to overwrite an existing tag name.

-f retagging is dangerous if the tag has already been pushed
Moving a tag that has already been pushed to a remote creates inconsistency: other developers who have fetched the tag still have the old version. They will not automatically get the new target, and some tooling may refuse to update a tag they have already fetched. If at all possible, prefer deleting and recreating the tag explicitly rather than using force-overwrite.

Force-move a local tag to a different commit

Bash
# Current state: v1.0.0 points to wrong commit
git log --oneline -4
# 9a8b7c6 (HEAD -> main) Hotfix: fix crash on login
# 3f8a2c9 (tag: v1.0.0) ← WRONG — this was accidentally included
# 7e4f1a2 Actual release commit   ← should be here
# b1c2d3e Previous work

# Move v1.0.0 to the correct commit
git tag -f v1.0.0 7e4f1a2
# Updated tag 'v1.0.0' (was 3f8a2c9)

# Verify
git log --oneline -4
# 9a8b7c6 (HEAD -> main) Hotfix: fix crash on login
# 3f8a2c9 Previous position of v1.0.0
# 7e4f1a2 (tag: v1.0.0) Actual release commit  ← now correct
# b1c2d3e Previous work

Force-move an annotated tag

Bash
# Must include -a when force-moving an annotated tag
git tag -f -a v1.0.0 7e4f1a2 -m "Release 1.0.0 (corrected)"
# Updated tag 'v1.0.0' (was 3f8a2c9)

After re-tagging: update the remote too

Bash
# After force-moving a tag locally, force-push to remote
git push origin --force v1.0.0
# To github.com:user/repo.git
#  + 3f8a2c9...7e4f1a2 v1.0.0 -> v1.0.0 (forced update)

# Warn your team so they can delete and re-fetch:
# git tag -d v1.0.0 && git fetch --tags
Comparison of deletion approaches

Action

Command

Affects remote?

Risk level

Delete local tag

git tag -d v1.0.0

No

Low — local only

Delete remote tag

git push origin --delete v1.0.0

Yes

Medium — affects all clones

Force-move local tag

git tag -f v1.0.0 <commit>

No

Low — local only

Force-move remote tag

git push origin --force v1.0.0

Yes

High — breaks other clones' local copies

Batch delete local

git tag -l "v0.*" | xargs git tag -d

No

Low — local only

Batch delete remote

git tag -l "v0.*" | xargs git push origin --delete

Yes

High if release tags

Common errors

Error: tag does not exist

Bash
git tag -d v9.9.9
# error: tag 'v9.9.9' not found.

# Fix: list available tags first
git tag | grep v9

Error: remote tag already deleted

Bash
git push origin --delete v1.0.0
# error: unable to delete 'v1.0.0': remote ref does not exist

# The tag was already deleted from the remote (or never pushed).
# Safe to ignore — just clean up locally if needed.
git tag -d v1.0.0

Error: tag exists — cannot overwrite without -f

Bash
git tag v1.0.0
# fatal: tag 'v1.0.0' already exists

# Fix: use -f to overwrite (see the warnings above)
git tag -f v1.0.0
Best practices for tag deletion
  • Delete local-only tags freely. If you never pushed a tag, removing it locally is completely safe and affects nobody.

  • Communicate before deleting shared tags. Post a message to your team before removing any tag from the remote.

  • Avoid deleting release tags. Release tags (v1.0.0, v2.3.1) are referenced by changelogs, deployment systems, and package registries. Deleting them breaks those links permanently.

  • Prefer annotating mistakes over deleting. Instead of deleting a release tag, consider creating a new patch release (v1.0.1) that fixes the issue.

  • Document force-moves. If you must move a tag, log the reason (with old and new commit SHA) in your project's CHANGELOG or release notes.

Use a script for coordinated remote tag cleanup
If you need to clean up many old pre-release tags from a remote, write a script that prints the list first for review, then prompts for confirmation before deleting. This prevents accidental deletion of important tags.