KhueApps
Home/DevOps/How to fix Git error: fatal: tag already exists

How to fix Git error: fatal: tag already exists

Last updated: October 07, 2025

What this error means

Git shows fatal: tag 'NAME' already exists when you try to create a tag with a name that’s already present in your local repository. If pushing, the server may reject with failed to push some refs because the tag exists remotely and you’re not forcing an update.

You must either:

  • Use a different tag name, or
  • Move (force-update) the tag to a new commit, or
  • Delete and recreate it (locally and/or on the remote).

Quickstart (safe defaults)

  1. Inspect the existing tag
  • View where it points and its message/signature:
git show v1.2.3
  1. Decide your intent
  • Keep tag as-is: do nothing; pick a new name for new release.
  • Move tag to a new commit (local):
git tag -f v1.2.3 <commit>
  • Delete local tag:
git tag -d v1.2.3
  1. Sync with remote
  • Delete remote tag (preferred before replacing):
git push origin :refs/tags/v1.2.3
  • Push new or moved tag:
git push origin v1.2.3
  • Alternatively, force-update remote tag in one step (if policy allows):
git push --force origin refs/tags/v1.2.3

Minimal working example

Reproduce the error and fix it.

# 1) Create a repo and a tag
mkdir demo-tags && cd demo-tags
git init
printf 'hello\n' > app.txt
git add app.txt
git commit -m "init"
git tag v1.0.0

# 2) Attempt to create the tag again (will fail)
# fatal: tag 'v1.0.0' already exists
git tag v1.0.0 || true

# 3) Make a new commit, then move the tag to it
printf 'feature\n' >> app.txt
git commit -am "feat: update"
# Move the tag to the new commit
git tag -f v1.0.0 HEAD
# Verify
printf 'Old: '; git rev-parse HEAD~1
printf 'Tag: '; git rev-parse v1.0.0

To sync with a remote after moving the tag:

# Remove remote tag then push the updated one
git push origin :refs/tags/v1.0.0
git push origin v1.0.0

Common scenarios and fixes

ScenarioCommand(s)Notes
Create a different tag namegit tag v1.0.1 HEADAvoid reusing released tags if consumers already rely on them.
Move existing tag locallygit tag -f v1.0.0 <commit>Use when correcting a mistaken tag before public release.
Delete local taggit tag -d v1.0.0Does not touch remote.
Delete remote taggit push origin :refs/tags/v1.0.0Requires permission; may be blocked by protected tags.
Force-update remote taggit push --force origin refs/tags/v1.0.0Risky if others depend on the tag. Prefer delete-then-push.
Recreate annotated taggit tag -d v1.0.0 && git tag -a v1.0.0 -m "msg" <commit>Tag type (annotated vs lightweight) is set on creation.
Recreate signed taggit tag -s v1.0.0 -m "msg" <commit>Needs GPG setup.

Annotated vs lightweight tags

  • Lightweight: pointer to a commit.
  • Annotated (-a/-s): full object with message, author, date; recommended for releases.
  • You cannot “convert” a tag; delete and recreate with desired type.

Remote tag already exists

  • Delete remote tag, then push your replacement.
  • If tags are protected (CI/CD policy), update settings or ask a maintainer.

Case sensitivity

  • Git refs (including tags) are case-sensitive. Prefer consistent lowercase to avoid confusion across platforms.

Step-by-step: updating a published tag safely

  1. Confirm whether the tag is published
git ls-remote --tags origin | grep -E "refs/tags/v1.2.3(\^\{\})?$" || true
  1. If published, notify stakeholders (CI, releases, downstreams). Rewriting tags can break reproducibility.
  2. Delete the remote tag
git push origin :refs/tags/v1.2.3
  1. Update or recreate locally
# Move to a commit
git tag -f v1.2.3 <commit>
# or recreate annotated
# git tag -d v1.2.3 && git tag -a v1.2.3 -m "Release 1.2.3" <commit>
  1. Push the tag
git push origin v1.2.3
  1. Retag builds/artifacts if necessary and update release notes.

Pitfalls

  • Breaking reproducibility: moving a released tag means old builds cannot be reproduced from that tag.
  • CI triggers: deleting/repushing tags can retrigger pipelines unexpectedly.
  • Protected tags: Git hosting may block deletion/force-push. Adjust protection or use admin UI.
  • Wrong commit: always verify with git show <tag> and git show <commit> before moving.
  • Mixed tag types: scripts may assume annotated tags; stay consistent.
  • Pushing all tags accidentally: git push --tags sends every local tag. Prefer pushing specific tags.

Performance notes

  • Tag operations are O(1) locally; the main cost is network when pushing/fetching.
  • Avoid git push --tags in large repos unless you intend to publish all tags.
  • To fetch only tags (and prune stale ones):
git fetch --tags --prune
  • Pushing a single tag transfers only its reachable objects; if the commit is already on the remote (typical), the transfer is small.
  • In CI, prefer explicit tag refspecs to minimize network usage:
git push origin refs/tags/v1.2.3

Tiny FAQ

  • How do I list tags?
git tag --list
  • How do I see where a tag points?
git rev-parse v1.2.3
git show v1.2.3
  • Can I rename a tag? No direct rename. Create the new tag, push it, then delete the old:
git tag new-name old-name
git tag -d old-name
git push origin new-name :refs/tags/old-name
  • Does moving a tag rewrite history? No. It moves a reference. Commits remain unchanged.

  • Why does git still complain after I delete locally? You likely have the tag on the remote. Delete it there, then push the local tag you want.

Series: Git

DevOps