Today I was inspecting some Git version tags. The repositories in question are using semantic versioning and they did not come in the order I expected.
This is an example from an open source repository of mine:
╰─ git tag
0.1.0
0.2.0
0.3.0
0.3.1
0.4.0
0.5.0
0.6.0
0.6.1
v0.10.0
v0.11.0
v0.12.0
v0.13.0
v0.13.1
v0.7.0
v0.8.0
v0.9.0
I attempted to pipe it to sort
, expecting it to fail.
╰─ git tag | sort
0.1.0
0.2.0
0.3.0
0.3.1
0.4.0
0.5.0
0.6.0
0.6.1
v0.10.0
v0.11.0
v0.12.0
v0.13.0
v0.13.1
v0.7.0
v0.8.0
v0.9.0
So I fired up my editor and wrote a small Perl script, since my experience with sorting in Perl is that it is pretty powerful.
#!perl
use warnings;
use strict;
use Data::Dumper;
use Getopt::Long;
my $reverse;
GetOptions ('reverse' => \$reverse) # flag
or die("Error in command line arguments\n");
# read all from standard input
my @tags = <STDIN>;
# remove newlines
chomp @tags;
my @sorted_tags = sort {
($b =~ /v?(\d+)\.\d+\.\d+/)[0] <=> ($a =~ /v?(\d+)\.\d+\.\d+/)[0]
||
($b =~ /v?\d+\.(\d+)\.\d+/)[0] <=> ($a =~ /v?\d+\.(\d+)\.\d+/)[0]
||
($b =~ /v?\d+\.\d+\.(\d+)/)[0] <=> ($a =~ /v?\d+\.\d+\.(\d+)/)[0]
||
fc($a) cmp fc($b)
} @tags;
# print sorted tags to standard output on separate lines
if ($reverse) {
print join("\n", reverse @sorted_tags), "\n";
} else {
print join("\n", @sorted_tags), "\n";
}
exit 0;
So now I can do:
╰─ git tag | sort_semantic_version_numbers.pl
v0.13.1
v0.13.0
v0.12.0
v0.11.0
v0.10.0
v0.9.0
v0.8.0
v0.7.0
0.6.1
0.6.0
0.5.0
0.4.0
0.3.1
0.3.0
0.2.0
0.1.0
And I even through in a --reverse
(-r
is the shortform):
╰─ git tag | sort_semantic_version_numbers.pl --reverse
0.1.0
0.2.0
0.3.0
0.3.1
0.4.0
0.5.0
0.6.0
0.6.1
v0.7.0
v0.8.0
v0.9.0
v0.10.0
v0.11.0
v0.12.0
v0.13.0
v0.13.1
There might a better approach, but this was done pretty fast. Yes the script possible lacks support for all sorts of tag formats, but it works for semantic version numbers and that works for my use-case.
Script available as a Gist.
Feedback, suggestions etc. most welcome.
Top comments (3)
It was no surprise to me that somebody would comment on my gist, with a better solution.
Apparently GNU
sort
can sort version numbers, so you can do:git tag | sort --version-sort
And
git tag | sort -r --version-sort
If you have GNU
sort
installed, which is a part of GNU Core Utils, meaning it can be installed on macOS using Homebrew.brew install coreutils
Since macOS already has a
sort
, you have to usegsort
git tag | gsort -r --version-sort
All the lessons learned have been collection in a TIL on the topic
That great would you love share the knowledge
I have indicated the MIT license in the inline documentation in Gist, it is not included here for brevity.