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?
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
Delete the tag on any remote before you push git push origin :refs/tags/
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
-f
to push the tags.
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.
Delete it with git tag -d <tagname>
and then recreate it on the correct commit.
I try to avoid a few things when using Git.
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.) The use of force when not required. 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.
git tag -a fix123 790a621265 # create a new local, annotaged tag
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
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 #"
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
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.
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
The above function was developed by referencing teerapap/git-move-annotated-tag.sh.
git tag -f -a my_tag
already preserves the message of a previous message (with git version 2.11.0).
Success story sharing
git push -f origin <tagname>
git push origin master --tags
is going to push tags, and themaster
branch if you have committed any changes to it locally. Just usegit push origin --tags
if all you want to do is push tags.