Batch delete git tags by dates

David Cai
2 min readMay 28, 2020

--

TLDR;

git for-each-ref --format '%(creatordate:iso) %(refname)' refs/tags | grep '2020-05-28 12:53' | sed -nE 's/.+refs\//:refs\//p' | xargs git push origingit fetch --prune origin +refs/tags/*:refs/tags/*
Tags

The other day, I accidentally created 60 git tags, and pushed all of them to the master branch. Oops!

Now I have a choice — delete them one by one, or delete them in a batch?

If the tags that I need to delete aren’t that many, I will just do:

git tags -d cat
git push origin :refs/tags/cat

The first command deletes tag “cat” in my local, and the second command deletes it in the remote.

But … I don’t want to repeat myself for 60 times...

So I came up with this:

git for-each-ref --format '%(creatordate:iso) %(refname)' refs/tags | grep '2020-05-28 12:53'

This command lists all tags created at 12:53 on May 28, 2020 — the time when I accidentally created “cat”, “dog”, “rat”, and other 57 tags related to small animals. The output looks like this:

2020-05-28 12:53:04 -0700 refs/tags/cat
2020-05-28 12:53:04 -0700 refs/tags/dog
2020-05-28 12:53:24 -0700 refs/tags/rat

“-0700” indicates my timezone.

The reason why I included date and time in the output is to double check the tags to make sure they are the ones I want to delete. Don’t want one mistake to lead to another, eh?

Then, I pipe this output to the powerful “sed” to remove date, time, and time zone, and replace “refs/” with “:refs/” which I will use later.

git for-each-ref --format '%(creatordate:iso) %(refname)' refs/tags | grep '2020-05-28 12:53' | sed -nE 's/.+refs\//:refs\//p'

The output looks like this:

:refs/tags/cat
:refs/tags/dog
:refs/tags/rat

Finally, I pipe the output as arguments to the “git push origin” command:

git for-each-ref --format '%(creatordate:iso) %(refname)' refs/tags | grep '2020-05-28 12:53' | sed -nE 's/.+refs\//:refs\//p' | xargs git push origin

This is equivalent to:

git push origin :refs/tags/cat :refs/tags/dog :refs/tags/rat

Of course, in my case, I have 60 tags to type. And that’s why I’d like to automatically generate all the tag names using the “git for-each-ref” command.

I also need to clean up the tags deleted in the remote but left in my local.

git fetch --prune origin +refs/tags/*:refs/tags/*

This command removes all tags present in my local but not in the remote.

To recap, these two commands are:

git for-each-ref --format '%(creatordate:iso) %(refname)' refs/tags | grep '2020-05-28 12:53' | sed -nE 's/.+refs\//:refs\//p' | xargs git push origingit fetch --prune origin +refs/tags/*:refs/tags/*

Of course, replace the date time with yours.

Happy coding!

--

--