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!