How can I move a tag on a git branch to a different commit?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Delete the old tag and recreate it on the target commit, then force-push to update the remote. For a lightweight tag, use git tag -f to overwrite in one step. For an annotated tag, delete and recreate to preserve a clean tagger timestamp and message.
Both approaches produce the same end result, but the delete-and-recreate method gives you a fresh tagger date and message, which matters for release tags that are displayed publicly.
Lightweight vs Annotated Tags
Git supports two types of tags, and the distinction affects how you should handle the move.
Lightweight tags are simple pointers to a commit, similar to a branch that never moves. They store no metadata.
Annotated tags are full Git objects with a tagger name, email, date, and message. They can be GPG-signed. These are the standard for release tagging.
When moving a tag, annotated tags deserve more care because the original tagger metadata does not automatically transfer. Using git tag -f -a creates a new annotation with the current timestamp.
Method 1: Force-Update the Tag
The quickest approach uses the -f (force) flag to overwrite the existing tag:
The --force on git push is necessary because the remote already has a ref named v1.2.3 pointing to a different object. Without --force, Git rejects the push.
Method 2: Delete and Recreate
This approach is more explicit and is preferred in team environments because each step is visible and reversible:
Finding the Target Commit Hash
If you do not already know the commit hash, find it with git log:
Updating Tags on the Remote
When a tag has been pushed to a remote (GitHub, GitLab, Bitbucket), other developers and CI pipelines may already reference it. Moving a remote tag requires force-pushing or a delete-then-push sequence.
Force-Push a Single Tag
Force-Push All Tags
Use --force --tags with caution. It overwrites every tag on the remote that differs from your local state, which can affect tags you did not intend to change.
Updating Specific Remote Refs
For more surgical updates, use the refspec syntax:
What Happens on GitHub and GitLab
On GitHub, tags are tied to releases. Moving a tag does not automatically update the associated release. The release still exists but now points to the new commit. If the release contains auto-generated changelogs or asset URLs that reference the old commit, those may become stale. You may need to edit the release manually.
On GitLab, tags are similarly used as release anchors. Moving a tag updates the tag reference, but existing pipelines triggered by the old tag's commit are not re-triggered unless you explicitly re-run them.
Comparison of Methods
| Method | Command | When to Use |
| Force-update | git tag -f <tag> <commit> | Quick local fix, solo development |
| Delete and recreate | git tag -d + git tag -a | Team environments, annotated tags |
| Force-push | git push --force origin <tag> | Updating a single remote tag |
| Refspec delete + push | git push origin :refs/tags/<tag> | Precise control over remote refs |
Notifying Your Team
Moving a tag that others have already fetched creates a discrepancy. Their local copy still points to the old commit. Team members need to update their local tags:
Without --force, git fetch --tags does not overwrite existing local tags. This is a deliberate safety measure by Git, which means team members must explicitly opt in to the update.
Automating Tag Verification
After moving a tag, verify that both local and remote point to the same commit:
Both commands should show the same commit hash. If they differ, the push did not go through or a fetch is needed.
Common Pitfalls
Forgetting --force when pushing an updated tag. Git refuses to update a remote tag that already exists unless you force it. The push will succeed silently (exit code 0) but the tag will not be updated. Always check the push output for rejection messages.
Not notifying the team after moving a remote tag. Other developers' local clones still have the old tag. Builds, deployments, and rollback scripts that reference the tag by name will use the stale commit until they run git fetch --tags --force.
Using git push --force --tags when you only want to move one tag. This overwrites all differing tags on the remote, which can accidentally move tags you did not intend to change. Push specific tags by name when possible.
Moving a tag that CI/CD uses as a deployment trigger. Many CI systems trigger pipelines on tag creation events. Moving a tag may or may not re-trigger the pipeline depending on the CI provider. GitHub Actions, for example, does not fire a new push event for a force-updated tag.
Losing the original annotation. Force-updating an annotated tag with git tag -f (without -a and -m) converts it to a lightweight tag. Always include -a and -m when force-updating annotated tags to preserve the annotation.
Summary
- Use
git tag -f <tagname> <commit>for a quick local move, or delete and recreate for a cleaner audit trail. - Always force-push (
git push --force origin <tagname>) after moving a tag that has been pushed to a remote. - Notify your team so they can run
git fetch --tags --forceto update their local copies. - Verify the move by comparing
git rev-parse <tagname>locally withgit ls-remote --tags origin <tagname>. - For annotated tags, always include
-aand-mto preserve the tag metadata.

