HOWTO · Git
How to Move an Existing Tag in Git
Move an existing Git tag to a chosen commit, update the remote tag when appropriate, and fetch a collaborator’s updated tag.
On this page
A Git tag names a specific point in repository history, usually a commit. You can move a local tag to a chosen commit and, if the team agrees, replace the remote reference too. Coordinate before changing a tag others use for a release: collaborators may have fetched the old target, and automated builds or release records may rely on it.
Understanding Git Tags and the Risks of Moving Them
A lightweight tag is a direct reference to a Git object, usually a commit. An annotated tag is a separate Git object containing a message and tagger metadata; it may also be signed. Replacing a tag changes which object the name resolves to. Recreating an annotated tag requires its message again, and recreating a signed tag requires signing it again. The new tag object does not preserve the old object or signature.
Before changing one, identify its current target with git show --no-patch --format=%H <tag> and decide which commit should replace it. Use a commit ID or another explicit revision for the new target rather than relying on whichever commit happens to be checked out. If the tag is shared, tell collaborators the intended replacement and let them know they may need to refresh their local copy.
Move a Local Tag to Another Commit
Use git tag -f <tag> <commit> to move a local tag directly. The -f option replaces the existing local name. For an annotated tag, recreate the annotation with git tag -f -a <tag> <commit> -m "<message>"; add -s in place of -a when the tag must be signed, and provide the signing setup required by your repository. Keep the original message and release meaning where appropriate.
Run this example in a shell with Git installed:
set -eu
repo_dir=$(mktemp -d)
trap 'rm -rf "$repo_dir"' EXIT
git -C "$repo_dir" init -q
git -C "$repo_dir" config user.name "Example User"
git -C "$repo_dir" config user.email "example@example.com"
printf 'first\n' > "$repo_dir/file.txt"
git -C "$repo_dir" add file.txt
git -C "$repo_dir" commit -qm "first commit"
first_commit=$(git -C "$repo_dir" rev-parse HEAD)
git -C "$repo_dir" tag v1.0 "$first_commit"
printf 'second\n' >> "$repo_dir/file.txt"
git -C "$repo_dir" commit -qam "second commit"
target_commit=$(git -C "$repo_dir" rev-parse HEAD)
git -C "$repo_dir" tag -f v1.0 "$target_commit" >/dev/null
tag_commit=$(git -C "$repo_dir" rev-parse refs/tags/v1.0)
if [ "$tag_commit" = "$target_commit" ]; then
printf 'tag points to intended commit: yes\n'
else
printf 'tag points to intended commit: no\n'
fi
For your repository, substitute the actual tag name and target commit. If a plain git tag <tag> <commit> reports that the tag already exists, that is expected: use the force option only after confirming the replacement target.
Update the Remote Tag
After coordinating, update only the named remote tag with git push --force origin <tag>. This replaces the remote reference for that tag; it does not make the change safe for collaborators who still use the prior target. Avoid pushing all tags when you intend to change just one. If the server rejects the update, check the repository’s permissions and server-side tag protections rather than repeatedly forcing the push.
Fetch a Tag Updated by Someone Else
If someone else moved the remote tag, your local tag may still point to its earlier target. Fetch the named tag with git fetch origin tag <tag>. If Git reports that fetching it would clobber the existing local tag, remove that local reference with git tag -d <tag> and fetch the named tag again. Deleting the local reference does not delete the remote tag. This error differs from a successful fetch that leaves a reference unchanged; a general git pull is not a reliable substitute for explicitly fetching this tag.
Verify the Tag Points to the Intended Commit
Check the local tag’s commit with git rev-parse <tag>^{}. The ^{} suffix peels an annotated tag to the commit it ultimately names. Compare that full commit ID with the intended commit, such as the ID returned by git rev-parse <commit>.
To inspect the remote without changing local refs, run git ls-remote --tags origin <tag>. This pattern selects the named tag and also matches its peeled reference. For an annotated tag, the line ending in ^{} gives the commit the tag ultimately names; compare that commit ID with the intended commit. After a collaborator changes a shared tag, communicate the new target so everyone can verify they have the same release reference.