1482

Today I was looking through the logs for a project and realized that I fat fingered a tag name some time ago. Is there some way to rename the tag? Google hasn't turned up anything useful.

I realize I could check out the tagged version and make a new tag, I even tried that. But that seems to create a tag object that isn't quite right. For one,

git tag -l

lists it out of order relative to all of the other tags. I have no idea if that's significant, but it leads me to believe that the new tag object isn't quite what I want. I can live with that, because I really only care that the tag name matches the documentation, but I'd rather do it "right", assuming there is a right way to do this.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Brandon Fosdick
  • 15,673
  • 4
  • 21
  • 20
  • Did you use the same invocation, i.e. if the old tag was annotated/signed tag, is the new tag also of this kind, or is it lightweight tag? – Jakub Narębski Jun 23 '09 at 08:07
  • 1
    Both the incorrect old tag, and the desired new tag, should be annotated and unsigned. The old tag was created with 'git tag -a bad_tag_name', so I'd like to do something along the lines of 'git tag -a good_tag_name'. – Brandon Fosdick Jun 23 '09 at 22:01
  • I should point out that I also want this magical tag rename process to preserve the annotation from the tag being renamed. Actually, I would really like to change just the name and nothing else. – Brandon Fosdick Jun 23 '09 at 22:09
  • 8
    `git log --oneline --decorate --graph` is helpful when cleaning up tags. – Joel Purra May 04 '12 at 18:00

11 Answers11

2530

Here is how I rename a lightweight tag old to new:

git tag new old           # Create a new local tag named `new` from tag `old`.
git tag -d old            # Delete local tag `old`.
git push origin new :old  # Push `new` to your remote named "origin", and delete
                          #     tag `old` on origin (by pushing an empty tag
                          #     name to it).

The colon in the push command removes the tag from the remote repository. If you don't do this, Git will create the old tag on your machine when you pull. Finally, make sure that the other users remove the deleted tag. Please tell them (co-workers) to run the following command:

git fetch --prune --prune-tags

Note that if you are renaming an annotated tag, you need to ensure that the new tag name is referencing the underlying commit and not the old annotated tag object that you're about to delete. If the old tag is an annotated tag, or you aren't sure, you can use ^{} to dereference the object until a non-tag object is found:

# create a new annotated tag "new" referencing the object
# which the old annotated tag "old" was referencing:
git tag -a new old^{}
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
Casey Watson
  • 51,574
  • 10
  • 32
  • 30
  • 16
    One thing to note is that if you use `git tag new old` is that "old" makes it into the "new" tag iff "old" is not a lightweight tag. To see that, try: `git tag -m tralala old; git tag new old; git tag -d old; git cat-file tag new | grep old`. That's because "new" points to the "old" tag, not to the commit "old" points to. – Uwe Kleine-König Dec 17 '13 at 16:43
  • 4
    To delete an old tag from the remote, you can also do `git push -d [remote] [tag]`. – Big McLargeHuge Jan 30 '19 at 21:36
  • https://confluence.atlassian.com/bitbucket/repository-tags-321860179.html was also helpful for me. – Ryan Sep 15 '19 at 22:31
  • 1
    @Stevoisiak is this still the case? Trying the mentioned solution the new tag is pointing to the same commit after doing all the steps – escapedcat Oct 02 '20 at 06:01
  • 1
    Following the suggested steps I noticed that the `new` tag lost the Note on Github, dang. Make sure you keep a copy of that so you can add that note back. – Jens Nov 28 '20 at 09:58
  • If you use my .gitconfig, then you just do `git retag old_tag new_tag` https://github.com/hopeseekr/BashScripts/blob/v2.3.0/gitconfig#L37-L38 – Theodore R. Smith Oct 30 '21 at 12:26
  • Renaming can lead to problems: when building my application I got the message `EXEC : warning : tag 'NewTag' is externally known as 'OldTag'.` If you do git show on the tag you can see the discripancy: `tag OldTag Tagger: The Author Date: Message commit c2345a (tag: NewTag) Author: The Author Date: Message diff --git a/NcCore/Helpers/NcUtils.cs b/NcCore/Helpers/NcUtils.cs index a2345..b12345 100644`. So better delete the old tag and recreate it as you did initially. – codingdave Feb 17 '23 at 11:53
  • Running the command `git pull --prune --tags` actually didn't work for me in one clone of my repo after I deleted the tags from another clone. I had to run `git fetch --prune --prune-tags` (from [this answer](https://stackoverflow.com/a/54297675/8705841)) for it to actually remove the renamed tag from the list. (I submitted an edit request to update the answer with this) – elkshadow5 Mar 13 '23 at 20:34
  • Windows users: the annotated tag must be quoted like "old^{}" or you will get "Failed to resolve 'old{}' as a valid ref." – dockd Jun 21 '23 at 00:38
325

The original question was how to rename a tag, which is easy: first create NEW as an alias of OLD: git tag NEW OLD then delete OLD: git tag -d OLD.

The quote regarding "the Git way" and (in)sanity is off base, because it's talking about preserving a tag name, but making it refer to a different repository state.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Greg McGary
  • 3,334
  • 1
  • 15
  • 2
137

In addition to the other answers:

First you need to build an alias of the old tag name, pointing to the original commit:

git tag new old^{}

Then you need to delete the old one locally:

git tag -d old

Then delete the tag on you remote location(s):

# Check your remote sources:
git remote -v
# The argument (3rd) is your remote location,
# the one you can see with `git remote`. In this example: `origin`
git push origin :refs/tags/old

Finally you need to add your new tag to the remote location. Until you have done this, the new tag(s) will not be added:

git push origin --tags

Iterate this for every remote location.

Be aware, of the implications that a Git Tag change has to consumers of a package!

jcupitt
  • 10,213
  • 2
  • 23
  • 39
kaiser
  • 21,817
  • 17
  • 90
  • 110
  • **Warning**: Using `git tag new old` will create a tag pointing to the old tag, *not* the old tag's commit. (See [*Why can't I checkout my tag from Git GUI?*](https://stackoverflow.com/q/49283734/3357935)) – Stevoisiak Mar 14 '18 at 17:30
  • 1
    @StevenVascellaro Thanks for the link. For the next time, please file an [edit] – answering is a community effort as well. Thanks. – kaiser Mar 14 '18 at 21:13
  • I didn’t make an edit because I have not tested the code for myself yet. (Note the submit date on the linked question) – Stevoisiak Mar 14 '18 at 21:26
  • Once we do `git tag new old^{}`, then we don't need `git tag new_tag_name old_tag_name` (the first step). – Number945 May 13 '18 at 07:04
  • 2
    I used this solution as a one-liner and it seemed to work like a charm! `git tag NEW_TAG OLD_TAG^{} && git tag -d OLD_TAG && git push origin :refs/tags/OLD_TAG && git push origin NEW_TAG` – MuffinTheMan Aug 27 '20 at 20:15
  • As mentioned in comments on other answers, the [https://git-scm.com/docs/git-tag#_discussion](https://git-scm.com/docs/git-tag#_discussion) link doesn't really apply here, since that discussion is about changing the commit a particular tag name points to, _not_ renaming a tag (i.e. creating a tag with a new name pointing at the same commit as an existing tag). – M. Justin Dec 11 '20 at 23:11
37

This wiki page has this interesting one-liner, which reminds us that we can push several refs:

git push origin refs/tags/<old-tag>:refs/tags/<new-tag> :refs/tags/<old-tag> && git tag -d <old-tag>

and ask other cloners to do git pull --prune --tags

So the idea is to push:

  • <new-tag> for every commits referenced by <old-tag>: refs/tags/<old-tag>:refs/tags/<new-tag>,
  • the deletion of <old-tag>: :refs/tags/<old-tag>

See as an example "Change naming convention of tags inside a git repository?".


hIpPy mentions in the comments:

I used rmandvikar/dotfiles bin/tag-cleanup to copy tags in bulk to a different naming format, and it worked like a charm.

#!/bin/sh

#usage:
#   ... | tag-cleanup
#
# Gen bulk-rename script for git tags from 'nuget-' to 'v'.

# todo: cleanup local tags
sed 's,nuget-,,' | \
    sed -E 's,(.+),nuget-\1 v\1,' | \
    sed -E 's,(.+) (.+),git push github refs/tags/\1:refs/tags/\2 :refs/tags/\1,' | \
    column -t -o ' '

hlpPy illustrates the use of the script with:

$ git tag | grep -F 'nuget-' | tag-cleanup 

I convert all tags from format nuget-1.2.3 to format v1.2.3.
I feel the nuget- tag naming format was an early mistake from me, and I wanted to fix it for a while now.

Tags now: rmandvikar/csharp-trie/tags.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Does this preserve annotations? – Brandon Fosdick Jun 21 '14 at 08:32
  • 1
    Beware that this **leaves the original tag name** in the annotation for annotated tags!! I'm not sure if that actually implies anything though, at least in the current versions. – gbr Aug 20 '15 at 18:26
  • @gbr Can you edit the answer with an example showing that "original tag name" left in the annotation? – VonC Aug 20 '15 at 18:27
  • 1
    @VonC I'm not sure I understand what you're asking; maybe I wasn't clear: the annotation objects contain a _tag_ field that's set to the tag's name, you can see it with `git cat-file -p `; with your method on my system I do get the 'renamed' tag ref (``), but its _tag_ field is still ``. – gbr Aug 20 '15 at 23:25
  • 4
    @gbr Isn't what the OP wanted? He mentioned "I should point out that I also want this magical tag rename process to preserve the annotation from the tag being renamed. Actually, I would really like to change just the name and nothing else" (http://stackoverflow.com/questions/1028649/how-do-you-rename-a-git-tag/24245862#comment846114_1028649) – VonC Aug 21 '15 at 05:33
  • I'm getting a warning when I do `git describe` immediately after using this approach: `warning: tag 'old-tag' is really 'new-tag' here``initial-tag` – M. Justin Dec 14 '20 at 17:05
  • 3
    Unlike most answers on this page, this preserves the tag date. – M. Justin Dec 14 '20 at 17:06
  • 1
    This is the best answer. – Sujit Dec 12 '21 at 05:25
  • I used this to copy tags in bulk to a different naming format, and it worked like a charm. (https://github.com/rmandvikar/dotfiles/blob/next/bin/tag-cleanup) – hIpPy Feb 12 '23 at 09:42
  • 1
    @hIpPy Interesting, thank you for the feedback. I have included your comment in the answer for more visibility. – VonC Feb 12 '23 at 10:31
  • @VonC, you may want to add this to showcase the usage of script, `$ git tag | grep -F 'nuget-' | tag-cleanup` where I convert all tags from format `nuget-1.2.3` to format `v1.2.3`. I feel the `nuget-` tag naming format was an early mistake from me, and I wanted to fix it for a while now. (tags now: https://github.com/rmandvikar/csharp-trie/tags) – hIpPy Feb 13 '23 at 00:02
  • @hIpPy Again, thank you. I have included your use case in the answer accordingly. – VonC Feb 13 '23 at 06:37
28

If it's published, you can't delete it (without risking being tarred and feathered, that is). The 'Git way' is to do:

The sane thing. Just admit you screwed up, and use a different name. Others have already seen one tag-name, and if you keep the same name, you may be in the situation that two people both have "version X", but they actually have different "X"'s. So just call it "X.1" and be done with it.

Alternatively,

The insane thing. You really want to call the new version "X" too, even though others have already seen the old one. So just use git-tag -f again, as if you hadn't already published the old one.

It's so insane because:

Git does not (and it should not) change tags behind users back. So if somebody already got the old tag, doing a git-pull on your tree shouldn't just make them overwrite the old one.

If somebody got a release tag from you, you cannot just change the tag for them by updating your own one. This is a big security issue, in that people MUST be able to trust their tag-names. If you really want to do the insane thing, you need to just fess up to it, and tell people that you messed up.

All courtesy of the man pages.

Community
  • 1
  • 1
Robert Munteanu
  • 67,031
  • 36
  • 206
  • 278
  • 6
    Or you can tag (with correct name) this incorrectly named tag. – Jakub Narębski Jun 23 '09 at 08:06
  • 8
    Thanks, I've been over that man page a million times already. Fortunately the bad tag hasn't been published anywhere. Even if it was, this is an internal project and I'm the only developer (for the moment). I'm think I'm fairly safe from both the tarring and the feathering, but only if I can get the repo to match the docs. – Brandon Fosdick Jun 23 '09 at 22:06
  • I sometimes use tags for my own personal references. Eg. it could be a 'ok_jb' tag. I use this, because some of the people I work with cannot build for my platform, so sometimes there will be build errors. I can then quickly get a version that builds, by checking out that tag. When the new sources builds, I just move the tag, or I rename it to builds##, where ## is a number (depending on the project). I may also emphasize when a special feature was introduced, by adding a tag. –  Oct 10 '14 at 02:04
  • 10
    Poor answer. "Don't do it" is never the correct answer to "How can I do it?". The user wasn't asking if you think it is a good idea to do that or if people will like that. If someone asks "How can I cut off my hand", either tell him how it's done or leave him alone but he won't need someone telling him that cutting of a hand may not be such a great idea. And you can do it. You can add a new tag and delete the old one, it's technically possible, even in a remote repository. – Mecki Nov 03 '15 at 15:08
  • 7
    This seems to answer the question "How do I make an existing tag point to a different revision?" instead of the OP's question, "How do I rename a tag?" It's also unclear how telling people you messed up is going to solve the problem (even though it's a good idea in general). – LarsH Mar 09 '16 at 19:49
27

As an add on to the other answers, I added an alias to do it all in one step, with a more familiar *nix move command feel. Argument 1 is the old tag name, argument 2 is the new tag name.

[alias]
    renameTag = "!sh -c 'set -e;git tag $2 $1; git tag -d $1;git push origin :refs/tags/$1;git push --tags' -"

Usage:

git renametag old new
Jared Knipp
  • 5,880
  • 7
  • 44
  • 52
  • 2
    This didn't work for me, since it failed at `!sh` (question was regarding Windows Git), however, after updating the format to the following, it worked: `renametag = "!f() { git tag $2 $1; git tag -d $1; git push origin :refs/tags/$1; git push --tags; }; f"`. – Sunny Patel Jun 21 '19 at 17:03
  • 1
    This could be made safer by changing `;` to `&&` so the command stops in case of error, rather than deleting/pushing tags even if e.g. the new tag creation failed. Also, could push just the new tag rather than doing a full push with all annotated & lightweight tags: `git push origin :$1 $2`. – M. Justin Dec 14 '20 at 22:22
  • 1
    Hey @SunnyPatel, I have added your amazing alias to my BashScripts gitconfig project. Thanks! https://github.com/hopeseekr/BashScripts/blob/v2.3.0/gitconfig#L37-L38 – Theodore R. Smith Oct 30 '21 at 12:25
  • @TheodoreR.Smith Glad it helped! I appreciate a shout out! :) – Sunny Patel Nov 05 '21 at 14:31
24

Follow the 3 step approach for a one or a few number of tags.

Step 1: Identify the commit/object ID of the commit the current tag is pointing to

command: git rev-parse <tag name>
example: git rev-parse v0.1.0-Demo
example output: db57b63b77a6bae3e725cbb9025d65fa1eabcde

Step 2: Delete the tag from the repository

command: git tag -d <tag name>
example: git tag -d v0.1.0-Demo
example output: Deleted tag 'v0.1.0-Demo' (was abcde)

Step 3: Create a new tag pointing to the same commit id as the old tag was pointing to

command: git tag -a <tag name>  -m "appropriate message" <commit id>
example: git tag -a v0.1.0-full  -m "renamed from v0.1.0-Demo" db57b63b77a6bae3e725cbb9025d65fa1eabcde
example output: Nothing or basically <No error>

Once the local git is ready with the tag name change, these changes can be pushed back to the origin for others to take these:

command: git push origin :<old tag name> <new tag name>
example: git push origin :v0.1.0-Demo v0.1.0-full
example output: <deleted & new tags>
M. Justin
  • 14,487
  • 7
  • 91
  • 130
vikas pachisia
  • 553
  • 5
  • 8
  • 1
    It is missing steps to push back deleted tag: `git push origin :refs/tags/v0.1.0-Demo` and to push back tags (with other pending things) `git push --tags` – Star Wolf Oct 03 '19 at 09:52
  • A downside to this exact approach is that it doesn't keep the existing tag's annotated message (though that's easily adjusted) – M. Justin Dec 12 '20 at 00:03
  • @StarWolf I edited the answer to add those details – M. Justin Dec 14 '20 at 22:30
  • I used `git show-ref --tags -d` to get a list of SHA in one terminal. Then I ended up chaining these all together since it seemed that my IDE kept pulling in remote tags :uhgg: ie: `git tag -d v19.12.27 && git tag -a v0.19.12-27 -m "renamed from v19.12.27" 6b8550023199938c9a679021ecc587a8e9427738 && git push origin :v19.12.27 v0.19.12-27` it would be nice to just make this a helper alias. I did notice mine complained about the tag being a nested tag, but I'm not sure what that means so I'm just moving forward with this. – CTS_AE Nov 11 '21 at 17:56
17

A duplicate annotated tag — including all tag info such as tagger, message, and tag date — can be created by using the tag info from the existing tag.

SOURCE_TAG=old NEW_TAG=new; deref() { git for-each-ref \
"refs/tags/$SOURCE_TAG" --format="%($1)" ; }; \
GIT_COMMITTER_NAME="$(deref taggername)" \
GIT_COMMITTER_EMAIL="$(deref taggeremail)" \
GIT_COMMITTER_DATE="$(deref taggerdate)" git tag "$NEW_TAG" \
"$(deref "*objectname")" -a -m "$(deref contents)"

git tag -d old

git push origin new :old

Update the SOURCE_TAG and NEW_TAG values to match your old and new tag names.

This command only addresses unsigned tags, though it should be a simple matter to extend this solution to signed tags.

Goal

To truly be an indistinguishable rename, all elements of an annotated tag should be the same in the new tag. The git-tag documentation specifies the parts of an annotated tag.

Tag objects (created with -a, -s, or -u) are called "annotated" tags; they contain a creation date, the tagger name and e-mail, a tagging message, and an optional GnuPG signature.

Answer motivation

From what I can tell, all the other answers have subtle gotchas, or don't fully duplicate everything about the tag (e.g. they use a new tag date, or the current user's info as the tagger). Many of them call out the re-tagging warning, despite that not applying to this scenario (it's for moving a tag name to a different commit, not for renaming to a differently named tag). I've done some digging, and have pieced together a solution that I believe addresses these concerns.

Procedure

An annotated tag named old is used in the example, and will be renamed to new.

Step 1: Get existing tag information

First, we need to get the information for the existing tag. This can be achieved using for-each-ref:

Command:

git for-each-ref refs/tags --format="\
Tag name: %(refname:short)
Tag commit: %(objectname:short)
Tagger date: %(taggerdate)
Tagger name: %(taggername)
Tagger email: %(taggeremail)
Tagged commit: %(*objectname:short)
Tag message: %(contents)"

Output:

Tag commit: 88a6169
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: old
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

Step 2: Create a duplicate tag locally

A duplicate tag with the new name can be created using the info gathered in step 1 from the existing tag.

The commit ID & commit message can be passed directly to git tag.

The tagger information (name, email, and date) can be set using the git environment variables GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, GIT_COMMITTER_DATE. The date usage in this context is described in the On Backdating Tags documentation for git tag; the other two I figured out through experimentation.

GIT_COMMITTER_NAME="John Doe" GIT_COMMITTER_EMAIL="j.doe@example.com" \
GIT_COMMITTER_DATE="Mon Dec 14 12:44:52 2020 -0600" git tag new cda5b4d -a -m "Initial tag

Body line 1.
Body line 2.
Body line 3."

A side-by-side comparison of the two tags shows they're identical in all the ways that matter. The only thing that's differing here is the commit reference of the tag itself, which is expected since they're two different tags.

Command:

git for-each-ref refs/tags --format="\
Tag commit: %(objectname:short)
Tagger date: %(taggerdate)
Tagger name: %(taggername)
Tagger email: %(taggeremail)
Tagged commit: %(*objectname:short)
Tag name: %(refname:short)
Tag message: %(contents)"

Output:

Tag commit: 580f817
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: new
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

Tag commit: 30ddd25
Tagger date: Mon Dec 14 12:44:52 2020 -0600
Tagger name: John Doe
Tagger email: <j.doe@example.com>
Tagged commit: cda5b4d
Tag name: old
Tag message: Initial tag

Body line 1.
Body line 2.
Body line 3.

As a single command, including retrieving the current tag data:

SOURCE_TAG=old NEW_TAG=new; deref() { git for-each-ref "refs/tags/$SOURCE_TAG" --format="%($1)" ; }; GIT_COMMITTER_NAME="$(deref taggername)" GIT_COMMITTER_EMAIL="$(deref taggeremail)" GIT_COMMITTER_DATE="$(deref taggerdate)" git tag "$NEW_TAG" "$(deref "*objectname")" -a -m "$(deref contents)"

Step 3: Delete the existing tag locally

Next, the existing tag should be deleted locally. This step can be skipped if you wish to keep the old tag along with the new one (i.e. duplicate the tag rather than rename it).

git tag -d old

Step 4: Push changes to remote repository

Assuming you're working from a remote repository, the changes can now be pushed using git push:

git push origin new :old

This pushes the new tag, and deletes the old tag.

M. Justin
  • 14,487
  • 7
  • 91
  • 130
  • Great! Just for signed messages, it invalidates them. To re-sign then, the last part of the single-liner must become: `-sm "$(deref contents:subject)\n\n$(deref contents:body)"` – ankostis May 06 '22 at 10:37
  • THIS is the only real answer! All others will create a new tag with wrong author and date. – Alex Oliveira Aug 07 '23 at 03:32
7

For the adventurous it can be done in one command:

mv .git/refs/tags/OLD .git/refs/tags/NEW
wolfc
  • 2,159
  • 1
  • 15
  • 7
  • 8
    This won't work if your refs are packed, i.e. if you've run `git gc` recently – forivall Dec 07 '12 at 01:21
  • 2
    This also will only affect the local repo. If you have a remote configured, I'm not sure what negative effects this could cause. I do not recommend this approach. – therealklanni May 09 '13 at 21:08
  • 2
    Note also that for annotated tags this will probably be even more troublesome, as the 'annotation' blob among the other things contains the original name of the tag. Actually I'm not sure if that's used by anything (hopefully at least by verify-tag), but I wouldn't take a chance. – gbr Aug 20 '15 at 18:12
  • 2
    @gbr This works just fine.(Of course, the note by @forivall is to be taken into account.) This trick has been massively used for ages in the ALT Sisyphus build system. Look at how the sources for a package are stored, e.g.: http://git.altlinux.org/gears/g/gear.git . The readable tags like **2.0.7-alt1** are the signed tags submitted by the maintainers to the build system. The cryptic tags **gb-sisyphus-task164472.200** are put there by the build system to track the task ID that has built&published the pkg from this source. They are dumb copies (`cp`), with the maintainer's message untouched. – imz -- Ivan Zakharyaschev May 11 '16 at 22:54
  • @imz--IvanZakharyaschev Good to know, I wouldn't put too much trust though that it won't give rise to problems in the future, with some product; there's no real specification of the git repositories format and expected interaction, so when it's viable I would strive to do things cleanly in the least surprising way – gbr May 13 '16 at 14:29
  • Simple. No side-effects. Worked fine for me on a local tag. – Petr Vepřek Feb 03 '18 at 23:00
  • 1
    @forivall If the refs are packed, the solution from https://stackoverflow.com/a/24245862/94687 will work with analogous effect: `git push . refs/tags/OLD:refs/tags/NEW` – imz -- Ivan Zakharyaschev Jun 16 '21 at 00:38
3

You can also rename remote tags without checking them out, by duplicate the old tag/branch to a new name and delete the old one, in a single git push command.

Remote tag rename / Remote branch → tag conversion: (Notice: :refs/tags/)

git push <remote_name> <old_branch_or_tag>:refs/tags/<new_tag> :<old_branch_or_tag>

Remote branch rename / Remote tag → branch conversion: (Notice: :refs/heads/)

git push <remote_name> <old_branch_or_tag>:refs/heads/<new_branch> :<old_branch_or_tag>

Output renaming a remote tag:

D:\git.repo>git push gitlab App%2012.1%20v12.1.0.23:refs/tags/App_12.1_v12.1.0.23 :App%2012.1%20v12.1.0.23

Total 0 (delta 0), reused 0 (delta 0)
To https://gitlab.server/project/repository.git
 - [deleted]               App%2012.1%20v12.1.0.23
 * [new tag]               App%2012.1%20v12.1.0.23 -> App_12.1_v12.1.0.23
zionyx
  • 1,927
  • 19
  • 14
3

Regardless of the issues dealing with pushing tags and renaming tags that have already been pushed, in case the tag to rename is an annotated one, you could first copy it thanks to the following single-line command line:

git tag -a -m "`git cat-file -p old_tag | tail -n +6`" new_tag old_tag^{}

Then, you just need to delete the old tag:

git tag -d old_tag

I found this command line thanks to the following two answers:

Edit:
Having encountered problems using automatic synchronisation of tags setting fetch.pruneTags=true (as described in https://stackoverflow.com/a/49215190/7009806), I personally suggest to first copy the new tag on the server and then delete the old one. That way, the new tag does not get randomly deleted when deleting the old tag and a synchronisation of the tags would like to delete the new tag that is not yet on the server. So, for instance, all together we get:

git tag -a -m "`git cat-file -p old_tag | tail -n +6`" new_tag old_tag^{}
git push --tags
git tag -d old_tag
git push origin :refs/tags/old_tag
Olivier
  • 303
  • 3
  • 14