Go and Git

Go Module Versions From Git Log

One of the more elegant design decisions the new Go Modules introduced is backwards compatibility with packages that don’t yet use semantic versioning by specifying a special version that includes a Git reference:

require v0.0.0-20180802-f77b0b28dc2b

The v0.0.0 makes it compatible with semantic versioning and ensures that if the package starts tagging their versions in the future, all versions are an upgrade over the special case. Meanwhile, the date makes sure that commits are sorted correctly (newer commits are higher “versions”). Finally, the commit or other reference lets the Go tool actually fetch the package from the repo just like it would have before modules were introduced (except now you can easily get a commit other than HEAD on the default branch).

All of this is great, but there’s just one problem: actually getting that version string is a pain in the ass. To be clear, any date works so you can always just write out the current date to make it sort correctly, and the number of digits in the hash isn’t important so normal short hashes or full hashes would work, but it still frustrates me when things aren’t consistent and I’d like to be able to reference the commit date and know about how old my dependencies are at a glance. To fix this, you can make Git spit out the version for you any time you run git log, just add the following to your ~/.gitconfig file (or to /etc/gitconfig to make a sytsem wide change, or .git/config in your repo if you want to change the format only for a specific repo):

  abbrev = 12
  pretty = %Cred%cd-%h%Creset %C(blue)%aN%Creset %C(yellow)%d%Creset %s %Cgreen(%cr)%Creset%+N
  abbrevCommit = true
  decorate = short
  date = "format:%G%m%d%H%M%S"

The value of pretty is just my personal preference, your mileage may vary, but the important part is the %cd-%h which spits out the commit date and hash, eg. 20180810141753-f6c9684b8d02. You can change the date format by modifying or the number of nibbles in the commit hash by modifying core.abbrev. This results in log lines like the following (from my package, with color elided):

20180821111446-8253112fd962 Sam Whited  (HEAD -> master, tag: v0.13.1, origin/master, origin/HEAD, freenas/master) xmlstream: add single token reader (5 weeks ago)
20180820234553-5186e1aeef84 Sam Whited  (tag: v0.13.0) xmlstream: remove Flush from TokenWriter (5 weeks ago)
20180818115214-acd593680ab3 Sam Whited  ci: test againsnt Go 1.11 RC1 (5 weeks ago)
20180818114938-d9dd79c0cfd2 Sam Whited  (tag: v0.12.3) xmlstream: add a TokenReadCloser interface (5 weeks ago)
20180810141753-f6c9684b8d02 Sam Whited  (tag: v0.12.2) ci: bump to Go 1.11 Beta 3 (6 weeks ago)
20180810141617-02c5add58b48 Sam Whited  xmlstream: add TeeReader (6 weeks ago)
20180802120635-4a6214452a60 Sam Whited  ci: don't test with -race (which fails on muscl) (8 weeks ago)
20180802120514-e9570575e36a Sam Whited  ci: add missing dep (git) (8 weeks ago)
20180802120414-cbe02477b431 Sam Whited  xmlstream: remove dep support (8 weeks ago)



I should also point out that this can be accomplished with command line flags as well as by modifying the config file. This is useful when automating package building, among other things:

git show --abbrev-commit --abbrev=12 --date='format:%G%m%d%H%M%S' \
  --pretty=format:v0.0.0_%cd_%h --no-patch HEAD

The Git logo was created by Jason Long and remixed under the terms of the Creative Commons Attribution 3.0 Unported license. The Go logo is copyright the Go Authors.