Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove remote git tags older than X months

Tags:

git

gitlab

I am trying to delete git tags that are older than X months

We have release tags that we need to retain, they are all tagged release-* where * = date

I know how to delete a singular tag git push origin :refs/tags/<tagName>

So I extrapolated to get all the remote tags to delete them

git ls-remote --tags origin | xargs git push origin :$1

To skip the release tags I was planning on using egrep -v making the command

git ls-remote --tags origin | egrep -v "(^\*|release*)" | xargs git push origin :$1

But I still haven't figured out how to do it by date.

Locally I can order things by date like so git for-each-ref --sort=taggerdate --format '%(refname)' refs/tags | egrep -v "(^\*|release*)" but that does not help me with remote tags.

If it helps I don't mind deleted or not deleting local tags in order to delete the remote ones.

Finally we use gitlab if it provides a better way of cleanup?

Regardless this needs to be something that can be run like a script through Jenkins to help with our git cleanup needs.

Update

Since we have thousand of git tags I realized that xargs is going to be rather slow.

I believe the way to delete will more likely be something like

git push origin $(< git tag | <sorting_by_date + exclude release> \ | sed -e 's/^/:/' | paste -sd " ")

That way the command will basically be appending :refs/tags/tag1 :refs/tags/tag2 into a single command instead of doing a unique delete for every tag and contacting the remote.

like image 520
wiredniko Avatar asked Feb 05 '18 18:02

wiredniko


2 Answers

After working on this for the past couple of days I figured out a solution that works quite well.

First collect all the git tags by chronological order, I excluded release* tags

git for-each-ref --sort=taggerdate --format '%(refname:short) %(taggerdate:short)' refs/tags | egrep -v "(^\*|release*)"

This will give the following output

master_7 2017-12-05
master_8 2017-12-05
master_9 2017-12-07
master_10 2017-12-08
master_11 2017-12-08
update_framework_1 2017-12-12
master_12 2017-12-12
master_13 2017-12-13

So it's the name of the tag separated by a space and then the date in YYYY-MM-DD format. If you want a full date or something specific update taggerdate:short with something appropriate.

I then took the output and processed it line by line looking at the date and comparing it with my cut off date.

This allowed me to generate a list of tags to delete.

Then I run the deletions by looping through the tag list and performing the following command

git push origin :refs/tags/<tag1> :refs/tags/<tag2>

I played it safe and run the command every 50 tags, but git didn't seem to have any problems with this.

Finally after all the deletions are complete I run git fetch --prune origin +refs/tags/*:refs/tags/* which deletes all local tags that do not exist in the remote.

And there you have it all tags are cleaned up.

like image 128
wiredniko Avatar answered Sep 21 '22 13:09

wiredniko


You'll need to be pretty specific about your source for a date stamp, as there are multiple candidates:

  • the tag name itself, or
  • the annotated tag object, if the tag is an annotated tag, or
  • the commit to which the tag ultimately points, perhaps via intermediate object(s) (annotated tag(s)).

Of these, only the first is immediately available via git ls-remote: to get the rest, you must have the objects available locally, so that you can read them and extract their embedded (encoded-via-text) date stamps.

You can fetch tags and their target objects using git fetch --tags origin, which is mostly the same as running, e.g., `git fetch origin '+refs/tags/:refs/tags/'. But if you want to make sure that your repository does not pick up their tags as your tags, you might want to fetch these into a separate name-space, such as:

git fetch origin '+refs/tags/*:refs/rtags/origin/*'

so that whatever their (origin's) repository has tagged as refs/tags/v12.34, for instance, now appears in your repository under the name refs/rtags/origin/v12.34. You can now read the name: v12.34, under the refs/rtags/origin/ space.

You can then use the full name to read the tagged Git object. If the tagged object is an annotated tag, you can extract its metadata, including its date. If the tagged object is a commit, you can read its metadata.

If the tagged object is an annotated tag, you can read its object metadata and continue reading objects ("peeling" the tag) until you find the final object; or you can have Git do this for you, using the name^{commit} or name^{} syntax. Note that the name^{commit} syntax directs Git to peel the tag until it reaches a commit, or else exit with an error, so that if the annotated tag eventually points to something else—such as a blob object—you catch this error. The name^{} syntax directs Git to peel the tag until it reaches any non-annotated-tag object, i.e., commit, tree, or blob.

like image 26
torek Avatar answered Sep 19 '22 13:09

torek