#development #git #golang

A common use-case for build-time variables is to inject the Git version information in the binary. There are several approaches on how to do this, but this one is the one I found the most useful one.

Let's start with creating a sample project using Go modules:

$ mkdir example-go-build-time-variables
$ cd example-go-build-time-variables
$ go mod init github.com/pieterclaerhout/example-go-build-time-variables
go: creating new go.mod: module github.com/pieterclaerhout/example-go-build-time-variables

As we want to play with the Git revision and branch info, let's also initialize it as a Git repository:

$ echo "# example-go-build-time-variables" >> README.md
$ git init
Initialized empty Git repository in ~/example-go-build-time-variables/.git/
$ git add .
$ git commit -m "first commit"
[master (root-commit) 47c55c2] first commit
 2 files changed, 4 insertions(+)
 create mode 100644 README.md
 create mode 100644 go.mod

Let's start with creating the most simple app we can think of by adding a main.go file with the following contents:

main.go

1package main
2
3import (
4    "fmt"
5)
6
7func main() {
8    fmt.Println("Hello stranger!")
9}

Let's also create a package called version in which the version information is going to be stored:

version/version.go

1package version
2
3// GitRevision will be injected with the current git commit hash
4var GitRevision string
5
6// GitBranch will be injected with the current git branch name
7var GitBranch string

I prefer to create a non-related package just containing this information. This makes it easy to access the version information from anywhere.

We can then update the main.go file to use this information:

main.go

 1package main
 2
 3import (
 4    "fmt"
 5
 6    "github.com/pieterclaerhout/example-go-build-time-variables/version"
 7)
 8
 9func main() {
10    fmt.Println("Git Revision:", version.GitRevision)
11    fmt.Println("Git Branch:", version.GitBranch)
12}

If we build and run it, you'll get the following output:

$ go build -o example-go-build-time-variables .
$ ./example-go-build-time-variables
Git Revision:
Git Branch:

That's the expected behaviour as we didn't inject the version information yet.

To inject the information, you need to specify the -ldflags option during the go build process. You can test it manually by changing the build command to:

$ go build -o example-go-build-time-variables -ldflags "-X github.com/pieterclaerhout/example-go-build-time-variables/version.GitRevision=revision -X github.com/pieterclaerhout/example-go-build-time-variables/version.GitBranch=branch" .
$ ./example-go-build-time-variables
Git Revision: revision
Git Branch: branch

Now, the only thing we need to do is to get the proper Git revision and branch name. The revision can be found with the following command:

$ git rev-parse --short HEAD
47c55c2

The branch name is obtained by the following command:

$ git rev-parse --abbrev-ref HEAD | tr -d '\040\011\012\015\n'
master

To make it easier, I usually combine everything in a simple Makefile which looks as follows:

 1APPNAME := example-go-build-time-variables
 2PACKAGE := github.com/pieterclaerhout/example-go-build-time-variables/version
 3
 4REVISION := $(shell git rev-parse --short HEAD)
 5BRANCH := $(shell git rev-parse --abbrev-ref HEAD | tr -d '\040\011\012\015\n')
 6
 7build:
 8    go build -ldflags "-X $(PACKAGE).GitRevision=$(REVISION) -X $(PACKAGE).GitBranch=$(BRANCH)" -o $(APPNAME)
 9
10run: build
11    ./$(APPNAME)

You can then simply run either make build to create the build or make run to build and run the application:

make run
go build -ldflags "-X github.com/pieterclaerhout/example-go-build-time-variables/version.GitRevision=47c55c2 -X github.com/pieterclaerhout/example-go-build-time-variables/version.GitBranch=master" -o example-go-build-time-variables
./example-go-build-time-variables server
Git Revision: 47c55c2
Git Branch: master

The complete source code for this example can be found here.