How can I delete a Git tag that has already been pushed?
29 Answers
You can push an 'empty' reference to the remote tag name:
git push origin :tagname
Or, more expressively, use the --delete
option (or -d
if your git version is older than 1.8.0):
git push --delete origin tagname
Note that git has tag namespace and branch namespace so you may use the same name for a branch and for a tag. If you want to make sure that you cannot accidentally remove the branch instead of the tag, you can specify full ref which will never delete a branch:
git push origin :refs/tags/tagname
If you also need to delete the local tag, use:
git tag --delete tagname
Background
Pushing a branch, tag, or other ref to a remote repository involves specifying "which repo, what source, what destination?"
git push remote-repo source-ref:destination-ref
A real world example where you push your master branch to the origin's master branch is:
git push origin refs/heads/master:refs/heads/master
Which because of default paths, can be shortened to:
git push origin master:master
Tags work the same way:
git push origin refs/tags/release-1.0:refs/tags/release-1.0
Which can also be shortened to:
git push origin release-1.0:release-1.0
By omitting the source ref (the part before the colon), you push 'nothing' to the destination, deleting the ref on the remote end.

- 2,864
- 1
- 24
- 44

- 81,148
- 4
- 36
- 39
-
259+1 for both answering the question and explaining the general case, and detailing the unabridged syntax's meaning – Peter Host Sep 14 '12 at 19:03
-
120And just in case someone wonders how to delete multiple tags at a time you simple list them using white space, e.g. `git push --delete origin tag1 tag2`. Same is valid for local tags deletion `git tag -d tag1 tag2` – Dmitry May 28 '14 at 00:54
-
10If tag name collides with a branch name you may end up with deleting your branch. Ha-ha. See the second answer - it's more ecological – zuba Dec 26 '16 at 09:56
-
The background helped me a lot to understand when i got an error: `error: dst refspec "my-tag" matches more than one. error: failed to push some refs` that I could execute `git push origin :refs/tags/my-tag` to specifically delete only the tag, and not the branch. – JamesWilson May 04 '18 at 13:36
-
5It is also interesting to know that `git tag -d \`git tag\`` will delete all local tags. Same applies for `git push --delete origin \`git tag\`` assuming you pulled the remote tags locally. That was handy in a test environment. – DarkFranX Jul 31 '18 at 15:15
-
Apparently (at least in GitLab) changing (and thus deleting) tags is a capability disjoint from that of creating a tag: `remote: GitLab: You are not allowed to change existing tags on this project.` (in response to trying to remove a tag that I erroneously created). – jhfrontz Sep 28 '18 at 14:34
-
4The fact we're at 6700+ upvotes and that it is this freaking complicated probably means it could be redesigned. – LMS5400 Aug 31 '21 at 21:31
-
1perfect answer, thank you. once I deleted the remote tags, the simplest way to sync locally without running again all tagnames is to prune: `git fetch --prune --prune-tags` – Chris Jan 05 '22 at 15:24
A more straightforward way is
git push --delete origin YOUR_TAG_NAME
IMO prefixing colon syntax is a little bit odd in this situation
-
7I think this is the proper way... other syntax look more like hacks to me. – Luigi R. Viggiano Dec 24 '12 at 17:45
-
20This works. One addition: If you have a branch and a tag with the same name, you can put the word `tag` before your tag name to make sure you get the tag, not the branch. – andypaxo Mar 27 '13 at 20:08
-
13@andypaxo What the command takes is refspecs, the correct way would be prefixing the tags with `refs/tags/`, like this: `refs/tags/v2.3.1`. – p3lim Mar 13 '15 at 05:04
-
I had 'bad' tag name created on remote server somehow, which had special characters, so I can't sync with that, so simply removed that with your suggestion: git push --delete origin "service--
--151" , can't remove it not with intellij, not with stash, not with sourceTree. Thanks ! – Dmitri Algazin Apr 12 '19 at 14:54 -
2For those reading this long after the answer was posted, at the time, the (now accepted) answer did not have this content in it; later on this answer's content was (very narrowly) suggested edit'd in to the accepted one. This is one of those weird edge cases where Stack Overflow's "the best answer rises to the top system" kinda fails, on one hand I'm happy the accepted answer has the right information because most readers won't look past the top answer, but I'm not thrilled as to how we got here... I hope future readers will not think this answer is just a copy/paste. – jrh Mar 05 '20 at 16:17
If you have a remote tag v0.1.0
to delete, and your remote is origin
, then simply:
git push origin :refs/tags/v0.1.0
If you also need to delete the tag locally:
git tag -d v0.1.0
See Adam Franco's answer for an explanation of Git's unusual :
syntax for deletion.
-
2
-
I got `fatal: remote part of refspec is not a valid name in :/refs/tags/0.0.1` ...? – Chaim Eliyah Sep 13 '16 at 23:17
-
3
-
5Better answer, as this also works if you have a branch and a tag that's called the same. – Erik A. Brandstadmoen Feb 05 '18 at 08:25
-
-
best answer. explaining that actually you push the same tag that you want to delete, and not for example the previous one – tikej Dec 02 '21 at 13:32
Delete all local tags and get the list of remote tags:
git tag -l | xargs git tag -d
git fetch
Remove all remote tags
git tag -l | xargs -n 1 git push --delete origin
Clean up local tags
git tag -l | xargs git tag -d

- 48,881
- 23
- 151
- 196

- 6,138
- 3
- 23
- 11
-
3How to remove all tags from the local and remote repos. This is what I was looking for, thanks! – Jorge Orpinel Pérez Aug 25 '14 at 17:12
-
git fetch, delete remote and then clean up locals, worked beautifully! – DiegoRBaquero Jan 28 '17 at 16:02
-
-
but,when the other one exec git-push, all the deleted tags will be reserved – flyflydogdog Mar 15 '22 at 03:46
git push --delete origin $TAGNAME
is the correct approach (in addition of a local delete).
But: make sure to use Git 2.31+ (Q1 2021).
"git push $there --delete
"(man) should have been diagnosed as an error, but instead turned into a matching push, which has been corrected with Git 2.31 (Q1 2021).
See commit 20e4164 (23 Feb 2021) by Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
-- in commit 1400458, 25 Feb 2021)
push
: do not turn--delete ''
into a matching pushNoticed-by: Tilman Vogel
When we added a syntax sugar "
git push remote --delete
"(man)<ref>
to "git push
"(man) as a synonym to the canonicalgit push remote
(man) : syntax at f517f1f ("builtin-push
:add
(man)--delete
as syntactic sugar for :foo", 2009-12-30, Git v1.7.0-rc0 -- merge), we weren't careful enough to make sure that<ref>
is not empty.Blindly rewriting "
--delete <ref>
" to ":<ref>
" means that an empty string<ref>
results in refspec ":
", which is the syntax to ask for "matching" push that does not delete anything.Worse yet, if there were matching refs that can be fast-forwarded, they would have been published prematurely, even if the user feels that they are not ready yet to be pushed out, which would be a real disaster.

- 1,262,500
- 529
- 4,410
- 5,250
-
1it works! damn, why they don't put this option on github in releases. I was doing an update of the same tag with elder zips. it took me a while to notice date was not ok. and then I did several tries, until I saw this page. – Uneconscience UneSource Oct 13 '22 at 12:28
From your terminal, do this:
git fetch
git tag
git tag -d {tag-name}
git push origin :refs/tags/{tag-name}
Now go to Github.com and refresh, they disappear.

- 4,555
- 31
- 31
- 45

- 30,478
- 7
- 87
- 83
git tag -d your_tag_name
git push origin :refs/tags/your_tag_name
The first line deletes your_tag_name
from local repo and second line deletes your_tag_name
from remote repo.
For those who use GitHub, one more step is needed: discarding draft.

- 2,345
- 27
- 29
This two steps works fine:
# delete local tag '1.0.0'
git tag -d 1.0.0
# delete remote tag '1.0.0' (eg, GitHub version too)
git push origin :refs/tags/1.0.0

- 4,834
- 3
- 44
- 62
To remove the tag from the remote repository:
git push --delete origin TAGNAME
You may also want to delete the tag locally:
git tag -d TAGNAME

- 12,296
- 4
- 32
- 39
-
so one line to do both: ``git push --delete origin TAGNAME && git tag -d TAGNAME`` – sakurashinken Aug 14 '19 at 17:49
Delete local tag '12345'
git tag -d 12345
Delete remote tag '12345' (eg; GitHub version too)
git push origin :refs/tags/12345
alternative approach
git push --delete origin tagName
git tag -d tagName

- 4,765
- 8
- 40
- 57
Just notice that, if you have a remote branch named as a remote tag, these commands are ambiguous:
git push origin :tagname
git push --delete origin tagname
So you must use this command to delete the tag:
git push origin :refs/tags/<tag>
and this one to delete the branch:
git push origin :refs/heads/<branch>
If not, you would get an error like this:
error: dst refspec <tagname> matches more than one.
error: failed to push some refs to '<repo>'

- 12,111
- 21
- 91
- 136

- 489
- 5
- 11
-
Short and concise. This post along with MeganZhou's popped out as being the answer to why we were having issues, the branchname and tagname were identical. I deleted the local tag and pushed to :refs/tags and all was good. – rwheadon Aug 29 '17 at 22:56
If you have created a tag called release01
in a Git repository you would remove it from your repository by doing the following:
git tag -d release01
git push origin :refs/tags/release01
To remove one from a Mercurial repository:
hg tag --remove featurefoo
Please reference https://confluence.atlassian.com/pages/viewpage.action?pageId=282175551
Up to 100x faster method for thousands of remote tags
After reading through these answers while needing to delete over 11,000 tags, I learned these methods relying or xargs
take far too long, unless you have hours to burn.
Struggling, I found two much faster ways. For both, start with git tag
or git ls-remote --tags
to make a list of tags you want to delete on the remote. In the examples below you can omit or replace sorting_proccessing_etc
with any grep
ing, sort
ing, tail
ing or head
ing you want (e.g. grep -P "my_regex" | sort | head -n -200
etc) :
This first method is by far the fastest, maybe 20 to 100 times faster than using xargs
, and works with a least several thousand tags at a time.
git push origin $(< git tag | sorting_processing_etc \
| sed -e 's/^/:/' | paste -sd " ") #note exclude "<" for zsh
How does this work?
The normal, line-separated list of tags is converted to a single line of space-separated tags, each prepended with :
so . . .
tag1 becomes
tag2 ======> :tag1 :tag2 :tag3
tag3
Using git push
with this format tag pushes nothing into each remote ref, erasing it (the normal format for pushing this way is local_ref_path:remote_ref_path
).
Method two is broken out as a separate answer elsewhere on this same page
After both of these methods, you'll probably want to delete your local tags too.
This is much faster so we can go back to using xargs
and git tag -d
, which is sufficient.
git tag | sorting_processing_etc | xargs -L 1 git tag -d
OR similar to the remote delete:
git tag -d $(< git tag | sorting_processing_etc | paste -sd " ")

- 1,117
- 8
- 18
-
You should split this into a few different answers. The answer with multiple tags on one line is, without a doubt, the right answer for bulk tag deletion. It's actually a little difficult to find this info nearly anywhere else. Even knowing what I'm looking for I have a hard time finding it in the git help page :) So kudos to you and highlight that as the right answer, and move the GitHub API one to a different place. And finally, the deleting tags locally, in bulk, works with space delimited tags (get rid of the colons) – CubanX Jul 18 '17 at 13:16
-
Thanks for the praise and suggestions. I will split this up. I don't understand your comment about local tag deletion. I don't think my final command snippet uses any colons, but I'm on mobile so maybe missing something. – TonyH Jul 18 '17 at 13:33
-
Sorry, I just meant that what you're doing to delete remote tags, works with deleting local tags, providing the entire list at once. :) Just instead of git push origin :tag1 :tag2 etc. you'd do git tag --delete tag1 tag2 tag3 that way you can have a total cleanup. Again, thanks a ton! – CubanX Aug 03 '17 at 14:00
If you use SourceTree - a great Git GUI - then you can easily do this without the command line by doing the following:
- Open your repository in SourceTree
- Select and expand the "Tags" tab on the left
- Right-Click on the tag you want deleted
- Select "Delete YOUR_TAG_NAME"
- In the verification window, select "Remove Tag From Remotes"
YOUR_TAG_NAME will now be removed from your local repository and all remotes - be it GitHub, BitBucket, or wherever else you listed as a remote for that repository.
Also, if you deleted a tag locally but not on the remote origins, and you want to delete it everywhere, then just create a new tag that has the same name and is attached at the same commit as the origins. Then, repeat the steps above to delete everywhere.

- 3,158
- 33
- 24
-
1Note that *this is safe* and will not delete any commit - only the tag itself – Chris Halcrow Jun 09 '21 at 23:27
Simple script to remove given tag from both local and origin locations. With a check if tag really exists.
if [ $(git tag -l "$1") ]; then
git tag --delete $1
git push --delete origin $1
echo done.
else
echo tag named "$1" was not found
fi
How to use:
- Create shell script file (e.g. git-tag-purge.sh) and paste content.
- chmod your script file to make it executable.
- Make the script globally available
- cd to your git project
- Call script (e.g.
$>git-tag-purge.sh tag_name
)

- 81
- 1
- 3
As @CubanX suggested, I've split this answer from my original:
Here is a method which is several times faster than xargs
and may scale much more with tweaking. It uses the Github API, a personal access token, and leverages the utility parallel
.
git tag | sorting_processing_etc | parallel --jobs 2 curl -i -X DELETE \
https://api.github.com/repos/My_Account/my_repo/git/refs/tags/{} -H
\"authorization: token GIT_OAUTH_OR_PERSONAL_KEY_HERE\" \
-H \"cache-control: no-cache\"`
parallel
has many operating modes, but generally parallelizes any command you give it while allowing you to set limits on the number of processes. You can alter the --jobs 2
parameter to allow faster operation, but I had problems with Github's rate limits, which are currently 5000/hr, but also seems to have an undocumented short-term limit as well.
After this, you'll probably want to delete your local tags too.
This is much faster so we can go back to using xargs
and git tag -d
, which is sufficient.
git tag | sorting_processing_etc | xargs -L 1 git tag -d
-
This seems much more complicated than the accepted answe. What is the benefit? – theUtherSide Sep 25 '17 at 22:43
-
3If you need to delete several thousand tags, then the speed is 10-100 times faster – TonyH Sep 25 '17 at 23:48
-
Thank you for clarifying. The OP asked about deleting a single tag. I couldnt imagine why someone would use this approach for a single tag. Perhaps this answer is better for another question involving deleting many tags – theUtherSide Sep 26 '17 at 00:28
-
I don't think it exists. I could create it to answer myself. Do you want to think that's appropriate? – TonyH Sep 26 '17 at 00:34
-
1
I wanted to remove all tags except for those that match a pattern so that I could delete all but the last couple of months of production tags, here's what I used to great success:
Delete All Remote Tags & Exclude Expression From Delete
git tag -l | grep -P '^(?!Production-2017-0[89])' | xargs -n 1 git push --delete origin
Delete All Local Tags & Exclude Expression From Delete
git tag -l | grep -P '^(?!Production-2017-0[89])' | xargs git tag -d

- 1,737
- 1
- 16
- 24
If you're using PowerShell, and you want to delete a bunch of them:
# Local tags:
git tag -l | foreach { git tag -d $_ }
# Remote tags:
git tag -l | foreach { git push --delete origin $_ }
Of course, you can also filter them before deleting:
git tag -l | Where-Object { $_ -like "build-*" } | foreach { git tag -d $_ }

- 11,775
- 1
- 54
- 60
For tortoise git users, at a scale of hundreds tags, you can delete multiple tags at once using UI, but the UI is well hidden under context menu.
From explorer windows right click -> Browse references -> Right click on ref/refmotes/name -> choose 'Delete remote tags'
See https://tortoisegit.org/docs/tortoisegit/tgit-dug-browse-ref.html

- 1,181
- 13
- 19
Delete a single tag:
# Local tag example:
git tag -d v1.0.0
# Remote tag example:
git push -d origin v1.0.0
Delete multiple tags:
# Local tag example:
git tag -d v1.0.0 v1.1.0
# Remote tag example:
git push -d origin v1.0.0 v1.1.0
Delete tags that match a particular pattern:
# Local tag example:
git tag -d $(git tag -l "*beta*")
# Remote tag example:
git push -d origin $(git tag -l "*beta*")

- 856
- 7
- 16
The other answers point out how to accomplish this, but you should keep in mind the consequences since this is a remote repository.
The git tag man page, in the On Retagging section, has a good explanation of how to courteously inform the remote repo's other users of the change. They even give a handy announcement template for communicating how others should get your changes.

- 8,310
- 3
- 49
- 52
Seems like a lot of work for something xargs
already does. Looking back through this thread, I'm guessing the slowness with xargs
that you experienced is because the original answer used xargs -n 1
when it didn't really need to.
This is equivalent to your method one except that xargs
automatically deals with the maximum command line length:
git tag | sorting_processing_etc | xargs git push --delete origin
xargs
can run processes in parallel too. Method 2 with xargs
:
git tag | sorting_processing_etc | xargs -P 5 -n 100 git push --delete origin
The above uses a maximum of 5 processes to handle a maximum of 100 arguments in each process. You can experiment with the arguments to find what works best for your needs.

- 41
- 1
-
Interesting. You learn something new about a Unix command everyday. I'll need to test my use case with this alternative. – TonyH Sep 25 '17 at 23:51
If you have a tag created starting with the # character, e.g. #ST002
, you might find that u are unable to delete using normal patterns. i.e.
git tag -d #STOO2
Will not delete the tag, but wrapping it in a String Literal like so
git tag -d "#ST002" or git tag -d '#ST002'
That will get it deleted. Hoping it will help someone who made the mistake of using # to write tag names.

- 316
- 2
- 6
To delete a tag on your remote repository, you can use
git push <remote> :refs/tags/<tagname>
The way to interpret the above is to read it as the null value, the value before the colon is being pushed to remote tag name.

- 41
- 1
Update 2023
First, delete a tag from the local repository.
To delete a local Git tag, use the git tag
command with the -d
option.
git tag -d <tag_name>
For example, you would run if you wanted to delete a local tag named v1.0
on your commit list.
git tag -d v1.0
If deleting is successful, you can see something like this output.
Deleted tag 'v1.0' (was 808b598)
List your existing tags using the tag command and the -l
option to ensure that tags were correctly deleted.
git tag -l
Second, delete the tag from the remote repository. To delete a remote Git tag, use the “git push” command with the “–delete” option and specify the tag name.
git push --delete origin <tag_name>
Back to the previous example, if you want to delete the remote Git tag named “v1.0”, you would run.
git push --delete origin v1.0
If deleting is successful, you can see something like this output.
To https://github.com/SCHKN/repo.git
- [deleted] v1.0
To delete a remote Git tag, use the git push
command and specify the tag name using the refs
syntax.
git push origin :refs/tags/<tag_name>
Back to the example, to delete a tag named v1.0
, you would run.
git push origin :refs/tags/v1.0
To https://github.com/SCHKN/repo.git
- [deleted] v1.0
Why should we specify the refs/tags
instead of just specifying the tag name?
Sometimes, your tag may have the same name as your branch.
If you tried to delete your Git tag without specifying the refs/tags
you would get the following error.
git push origin :v1.0
error: dst refspec v1.0 matches more than one.
error: failed to push some refs to '<repository>'
Consequently, you need to specify that you are trying to delete a Git tag and not a Git repository.

- 5,266
- 3
- 37
- 59
Just wanted to share an alias I created which does the same thing:
Add the following to your ~/.gitconfig
[alias]
delete-tag = "!f() { \
echo 'deleting tag' $1 'from remote/origin ausing command: git push --delete origin tagName;'; \
git push --delete origin $1; \
echo 'deleting tag' $1 'from local using command: git tag -d tagName;'; \
git tag -d $1; \
}; f"
The usage looks like:
-->git delete-tag v1.0-DeleteMe
deleting tag v1.0-DeleteMe from remote/origin ausing command: git push --delete origin tagName;
To https://github.com/jsticha/pafs
- [deleted] v1.0-DeleteMe
deleting tag v1.0-DeleteMe from local using command: git tag -d tagName;
Deleted tag 'v1.0-DeleteMe' (was 300d3ef22)

- 5,179
- 10
- 35
- 56

- 1,058
- 10
- 8
Here is a local testcase to test it locally without messing with a remote:
~/p $ mkdir gittest
~/p/git $ cd gittest/
~/p/gittest $ git init
Initialized empty Git repository in /Users/local_user/p/gittest/.git/
~/p/gittest $ touch testfile.txt
~/p/gittest $ git add testfile.txt
~/p/gittest $ git commit -m "initial commit"
[master (root-commit) 912ce0e] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 testfile.txt
~/p/gittest $ git tag
~/p/gittest $ git tag -a testtag
~/p/gittest $ git tag
testtag
~/p/gittest $ git show-ref
912ce0e40635c90241fdab756dce7ea34938de57 refs/heads/master
b0a6c15cabb990e6d6c46f762891b63608d962f3 refs/tags/testtag
~/p/gittest $ cd ..
~/p $ mkdir gitbare
~/p $ cd gitbare
~/p/gitbare $ git init --bare
Initialized empty Git repository in /Users/local_user/p/gitbare/
~/p/gitbare $ cd ..
~/p $ cd gittest/
~/p/gittest $ git remote add origin /Users/local_user/p/gitbare
~/p/gittest $ git push -u origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 215 bytes | 215.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /Users/local_user/p/gitbare
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
~/p/gittest $ git push origin testtag
Counting objects: 1, done.
Writing objects: 100% (1/1), 163 bytes | 163.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To /Users/local_user/p/gitbare
* [new tag] testtag -> testtag
~/p/gittest $ git show-ref
912ce0e40635c90241fdab756dce7ea34938de57 refs/heads/master
912ce0e40635c90241fdab756dce7ea34938de57 refs/remotes/origin/master
b0a6c15cabb990e6d6c46f762891b63608d962f3 refs/tags/testtag
~/p/gittest $ git push -d origin testtag
To /Users/local_user/p/gitbare
- [deleted] testtag
~/p/gittest git tag -d testtag
Deleted tag 'testtag' (was b0a6c15)
~/p/gittest $ git show-ref
912ce0e40635c90241fdab756dce7ea34938de57 refs/heads/master
912ce0e40635c90241fdab756dce7ea34938de57 refs/remotes/origin/master
~/p/gittest

- 2,982
- 1
- 26
- 29
There are a lot of good answers here already, but if you ever need to delete all the tags, this one liner using PowerShell can be used:
foreach($tag in (git tag)) { git tag -d $tag.Trim(); git push origin :refs/tags/$tag }
Here, we get the list of all tags, delete each local tag followed by deleting the remote tag (tested on GitHub).

- 1,026
- 2
- 15
- 32
This worked for me
git push --force origin refs/tags/<tag_name>:refs/tags/<tag_name>

- 61
- 4