My way of describing Ruby is somewhat peculiar, but there is method in my madness. Most discussions of Ruby explain it “from the bottom up” (starting with strings and arrays and hashes and working up to classes and modules); I explain it “from the top down” (starting with modules). That’s a deliberate pedagogical choice. I learned Ruby from the bottom up, and that made Ruby much harder, and take much longer, to understand; top-down explanation is better, and gives a clearer picture, right away, of how Ruby works.
— Matt Neuburg, Just Enough Ruby

a better version comparator

Back in February, I wrote a little Ruby script to deal with sorting version numbers as they’re dumped out of the git tag command. The problem (in a nutshell) is that "1.0.2" < "1.0.10" — except that git returns these as strings which sort alphabetically. Hence the original Ruby script.

Now: if you’re behaving yourself, and following “The Driessen Model" more/less to the letter, then you should only have properly formatted tags in your git repo(s) and this won’t be a problem. But we also know from experience that people will inevitably mess this up, be it through negligence, naiveté, and/or a good ol’ fashioned nonconformist spirit.

Now, that original script was good, but it had a few flaws. For one thing, it was destructive; you wouldn’t always get out what you put in. (For example, if you put in 1.2.3_04 then you would get back 1.2.304.) And though it dealt reasonably well with arbitrary depth, it also relied on some good ol’ fashioned “Ruby magic” to resolve some of the mis-matched version string lengths. (Although you could also argue that that was the reason to use Ruby instead of (fill in the blank) other language.)

So how do we deal with this more robustly? How do we deal with “semantic” tags (e.g., my-awesome-beta-feature) in the repo? (Which (as an aside) the original script would simply coerce into 0.) Or tags that follow the J2SE versioning recommendation (e.g., 1.2.3_04, as in our example above)?

Well, we could try something like this:

…which still isn’t perfect (i.e., it shoves “semantic” tags to the beginning of the list) but will handle both “dotted” and J2SE versions with aplomb and will fail much more gracefully and somewhat more predictably. Most importantly, the list you get out is the same as the list that you put in.

Also: the logic is a little more portable. Here’s the same comparator but implemented in Groovy:

Here is the Gist with all the source, the test tag list, all the revisions, and any other bonuses I manage to sneak in… Enjoy.

don’t get lost in the sea of tags

Ever feeling lost in a sea of not-exactly-ordered tags when you enter git tag at the command prompt? It seems that a common tagging idiom in a lot of git repos is to tag important milestones or releases. Some repos use <major>.<minor>, others <major>.<minor>.<version>, still others <major>.<minor>.<version>.<patch> (and so on?). And as those repos get along, so do their version numbers. And before long, they don’t all fit on the screen; and if the updates are frequent enough, you might find that you missed that latest tag because 1.0.1.21 was “off the screen” and what you thought was the latest (1.0.1.9) was already long out-of-date. But a little Ruby magic can make this all better:

And then (after optionally adjusting the Ruby script as meets your needs) add the following alias to your .gitconfig:

…and you should be good to go. No more mysteries. (It even gracefully handles tag suffixes like -beta.)

Tags: Ruby git