1254

I created a tag on the master branch called v0.1 like this:

git tag -a v0.1 

But then I realized there were still some changes I needed to merge into master for release 0.1, so I did that. But now my v0.1 tag is stuck on (to invoke the post-it note analogy) the wrong commit. I want it to be stuck on the most recent commit on master, but instead it is stuck on the second most recent commit on master.

How can I move it to the most recent commit on master?

0

13 Answers 13

1662

Use the -f option to git tag:

-f --force Replace an existing tag with the given name (instead of failing) 

You probably want to use -f in conjunction with -a to force-create an annotated tag instead of a non-annotated one.

Example

  1. Delete the tag on any remote before you push

    git push origin :refs/tags/<tagname> 
  2. Replace the tag to reference the most recent commit

    git tag -fa <tagname> 
  3. Push the tag to the remote origin

    git push origin --tags 
Sign up to request clarification or add additional context in comments.

22 Comments

This only works if you haven't pushed the code off your machine. If you have, the best answer is 'there's plenty of numbers in the world' as it's probably not worth the hassle.
If you had already pushed your tag you can still update the remote tag with a forced push git push -f origin <tagname>
You don’t have to use forced push, if the tag reference can be fast forwarded to the new place.
What is not mentioned here and in the docs is, that this indeed does move the tag message, if no new message is given.
Note that in #3 git push origin master --tags is going to push tags, and the master branch if you have committed any changes to it locally. Just use git push origin --tags if all you want to do is push tags.
|
453

To sum up if your remote is called origin and you're working on master branch:

git tag -d <tagname> # delete the old tag locally git push origin :refs/tags/<tagname> # delete the old tag remotely git tag <tagname> <commitId> # make a new tag locally git push origin <tagname> # push the new local tag to the remote 

Description:

  • Line 1 removes the tag in local env.
  • Line 2 removes the tag in remote env.
  • Line 3 adds the tag to different commit
  • Line 4 pushes the change to the remote

You can also change line 4 to git push origin --tags to push all of your local tag changes/updates to the remote repo.

The above answer is based on content in the question by @eedeep, as well as answers by Stuart Golodetz, Greg Hewgill, and @ben-hocking, and comments below their answers, and @NateS's original comments below my answer.

3 Comments

Line 4 works for pushing an explicit single updated tag to the remote repository, in case you don't want to update all tags, as I didn't.
Also, if you have a tag and a branch with the same name (e.g. 1.0.0) it will error out with error: src refspec 1.0.0 matches more than one. You can specify that you want to push a tag specifically by using git push origin tags/1.0.0
Exactly what I needed. I accidentally pushed my new tag before then committing and pushing my current changes, which attached it to a previous commit. This solved it for me.
359

More precisely, you have to force the addition of the tag, then push with option --tags and -f:

git tag -f -a <tagname> git push -f --tags 

3 Comments

This answer completed the accepted answer by including -f to push the tags.
If you don't want to add a comment, omit the -a.
"If you don't want to add a comment, omit the -a" -- meaning if you want to add a comment, add a -m "commit message here"
105

Delete it with git tag -d <tagname> and then recreate it on the correct commit.

4 Comments

@eedeep: I think Greg's response is actually better here to be fair.
Keep it simple. Delete it, do what you did before again.
This should be the accepted answer, for its simplicity. Also does not use -f force excessively.
@chinnychinchin. This is one place where use of force really is not excessive. It's no different than saying "accept mine" during a merge.
102

I try to avoid a few things when using Git.

  1. Using knowledge of the internals, e.g. refs/tags. I try to use solely the documented Git commands and avoid using things which require knowledge of the internal contents of the .git directory. (That is to say, I treat Git as a Git user and not a Git developer.)

  2. The use of force when not required.

  3. Overdoing things. (Pushing a branch and/or lots of tags, to get one tag where I want it.)

So here is my non-violent solution for changing a tag, both locally and remotely, without knowledge of the Git internals.

I use it when a software fix ultimately has a problem and needs to be updated/re-released.

git tag -d fix123 # delete the old local tag git push github :fix123 # delete the old remote tag (use for each affected remote) git tag fix123 790a621265 # create a new local tag git push github fix123 # push new tag to remote (use for each affected remote) 

github is a sample remote name, fix123 is a sample tag name, and 790a621265 a sample commit.

4 Comments

I think OPs tag was annotaged. The third line could be like this instead git tag -a fix123 790a621265 # create a new local, annotaged tag
I hate that this is the best answer. I wonder why it has to be so complicated? Tags are well suited for marking which commit is for production, so I need to change which commit it's tacked to quite often. Using a branch which you just rebase all the time is currently easier, but it's redundant when the environment is of no concern to your repository contents (something worth striving for).
@Zyl: Why use tags for tracking production HEAD? Branches are even better suited for that. Use a branch and fast-forward it most of the time when production upgrades. In case of regressions you can hard-reset the branch.
@DanielBöhmer That's what we ended up doing in most repos, but I can't tell you the amount of devs who do not understand that merging A into B does not guarantee equality of state. Communication and knowledge transfer are way glanced over in the industry, but they affect how we do things more than anything.
68

I'll leave here just another form of this command that suited my needs.
There was a tag v0.0.1.2 that I wanted to move.

$ git tag -f v0.0.1.2 63eff6a Updated tag 'v0.0.1.2' (was 8078562) 

And then:

$ git push --tags --force 

6 Comments

This did the trick and is the simplest answer. Thank you!
FYI: yhis does lose any message that was associated with the tag
@SaaruLindestøkke good to know! Too busy to test right now but I wonder if it can be fixed just by using -fa instead of -f.
@Nakilon I've tried it with th -fa option, but unfortunately it returns with an error: too many arguments.
Worked for me, despite being on a protected branch!
|
20

Remove locally:

git tag -d v0.1 

Remove on remote:

git push origin --delete v0.1 

Then re-add locally and push v0.1 to the most recent commit:

git tag -a v0.1 git push origin --tags 

1 Comment

Not needed ... you can use git tag -f name and it will move, git push --tags --force to move it on remote.
17

Alias to move one tag to a different commit.

In your sample, to move commit with hash e2ea1639 do: git tagm v0.1 e2ea1639.

For pushed tags, use git tagmp v0.1 e2ea1639.

Both alias keeps you original date and message. If you use git tag -d you lost your original message.

Save them on your .gitconfig file

# Return date of tag. (To use in another alias) tag-date = "!git show $1 | awk '{ if ($1 == \"Date:\") { print substr($0, index($0,$3)) }}' | tail -2 | head -1 #" # Show tag message tag-message = "!git show $1 | awk -v capture=0 '{ if(capture) message=message\"\\n\"$0}; BEGIN {message=\"\"}; { if ($1 == \"Date:\" && length(message)==0 ) {capture=1}; if ($1 == \"commit\" ) {capture=0} }; END { print message }' | sed '$ d' | cat -s #" ### Move tag. Use: git tagm <tagname> <newcommit> tagm = "!GIT_TAG_MESSAGE=$(git tag-message $1) && GIT_COMMITTER_DATE=$(git tag-date $1) && git tag-message $1 && git tag -d $1 && git tag -a $1 $2 -m \"$GIT_TAG_MESSAGE\" #" ### Move pushed tag. Use: git tagmp <tagname> <newcommit> tagmp = "!git tagm $1 $2 && git push --delete origin $1 && git push origin $1 #" 

Comments

14

One other way:

Move tag in remote repo.(Replace HEAD with any other if needed.)

$ git push --force origin HEAD:refs/tags/v0.0.1.2 

Fetch changes back.

$ git fetch --tags 

1 Comment

This is more "transactional" than the other answers.
6

If you use github and want change commit for release (for example you find that don't commit smth after creating release).You can use

git push origin :refs/tags/<tagname> 

After this command github delete your tag and your release will become a draft. It means you can recreate release and select commit. Your files and your message will be saved.

Comments

2

If the desired end result is updating the contents of a tag already on remote:

  1. git checkout <tag_name>
  2. Commit your changes
  3. git tag -f <tag_name>
  4. git push -f origin <tag_name>

Comments

1

If you want to move an annotated tag, changing only the targeted commit but preserving the annotation message and other metadata use:

moveTag() { local tagName=$1 # Support passing branch/tag names (not just full commit hashes) local newTarget=$(git rev-parse $2^{commit}) git cat-file -p refs/tags/$tagName | sed "1 s/^object .*$/object $newTarget/g" | git hash-object -w --stdin -t tag | xargs -I {} git update-ref refs/tags/$tagName {} } 

usage: moveTag <tag-to-move> <target>

The above function was developed by referencing teerapap/git-move-annotated-tag.sh.

1 Comment

It seems this is no longer needed: git tag -f -a my_tag already preserves the message of a previous message (with git version 2.11.0).
0

If needed to update all tags to the latest commit of the current branch:

for i in $(git tag); do git push origin ":refs/tags/$i" git tag -fa $i done git push origin --tags 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.