fatal: tag 'v1.0' already exists means the tag name is taken in your repository; ! [rejected] v1.0 -> v1.0 (already exists) means it is taken on the remote. To move the tag to a new commit, use git tag -f v1.0 locally and git push --force origin v1.0 for the remote, or, usually better, tag the fix with a new version number.

A plain push did not move the existing tag on the remote, and a clone that already had the old v1.0 kept it on both git fetch and git fetch --tags. If the tag was already published, a new tag such as v1.0.1 avoids two people meaning different commits by the same name.

The error

Creating the tag again locally:

PS> git tag v1.0
fatal: tag 'v1.0' already exists

Pushing a moved tag to a remote that already has it:

PS> git push origin v1.0
To ..\b6-remote.git
 ! [rejected]        v1.0 -> v1.0 (already exists)
error: failed to push some refs to '..\b6-remote.git'
hint: Updates were rejected because the tag already exists in the remote.

Why it happens

A tag is a name for one commit, meant to stay put. git tag NAME creates the name and refuses (exit code 128) when it exists, so it never silently moves a release marker. The push has the same rule: the remote already holds v1.0 pointing at the old commit, and a push may not change an existing tag without being forced.

The usual story: you tag v1.0, push it, find a last-minute bug, commit the fix and want v1.0 to include it. The local git tag v1.0 fails first; after git tag -f the local tag moves, and then the push fails.

The fix

Move the tag locally, then force that one tag on the remote:

PS> git tag -f v1.0
Updated tag 'v1.0' (was 8e0e663)
PS> git push --force origin v1.0
To ..\b6-remote.git
 + 8e0e663...b79ea5f v1.0 -> v1.0 (forced update)
PS> git ls-remote --tags origin
b79ea5f6beeed52482484cc0be9546397c2263c9	refs/tags/v1.0
PS> git rev-parse v1.0
b79ea5f6beeed52482484cc0be9546397c2263c9

git ls-remote shows the remote tag now points at the same commit as the local one. Naming the tag in the push (origin v1.0) keeps the force to that single ref. Teammates who already have the old v1.0 keep it: in a clone made before the tag moved, git fetch --tags refused the new one until it was forced:

PS> git fetch --tags
From C:/.../b6-remote
 ! [rejected]        v1.0       -> v1.0  (would clobber existing tag)
PS> git fetch --tags --force
From C:/.../b6-remote
 t [tag update]      v1.0       -> v1.0

After the tag moved once more, a plain git fetch in the same clone exited 0, updated origin/main, and left the local v1.0 on the old commit (7addd6e) while the remote's pointed at c432b2b, with no warning at all.

That is why a new version tag is the friendlier choice once a release is public.

How it was reproduced

Git for Windows 2.45.2 on Windows 11, Windows PowerShell 5.1, in a throwaway repository with a local bare repository as origin. v1.0 was created and pushed; after a further commit, git tag v1.0 exited with 128, and after git tag -f v1.0 the push exited with 1. git push --force origin v1.0 updated the remote tag, confirmed with git ls-remote --tags.

Frequently asked

How do I move an existing git tag to another commit?
Run git tag -f with the tag name on the commit you want, then git push --force origin with the tag name to update the remote.
Why is my git tag push rejected with already exists?
The remote already has a tag of that name pointing at a different commit, and a normal push does not change existing tags. Force that tag, or use a new tag name.
Should I move a release tag or create a new one?
Create a new one when the old tag has already been pushed and others may have fetched it. After a move, existing clones keep the old tag; their git fetch --tags is rejected with would clobber existing tag until they add --force.

More decoded errors in the Fixes category. When a branch push is rejected rather than a tag, see git push rejected (non-fast-forward).