How do you read debug VCS version info from a Go 1.18 binary?

Viewed 1118

I'm trying to read version control information from my Go binaries, but the build info doesn't seem to contain any VCS info.

From the Go 1.18 release notes:

The go command now embeds version control information in binaries. It includes the currently checked-out revision, commit time, and a flag indicating whether edited or untracked files are present. Version control information is embedded if the go command is invoked in a directory within a Git, Mercurial, Fossil, or Bazaar repository, and the main package and its containing main module are in the same repository. This information may be omitted using the flag -buildvcs=false.

Sample program:

package main

import (
    "fmt"
    "runtime/debug"
)

func main() {
    if bi, ok := debug.ReadBuildInfo(); ok {
        fmt.Printf("%+v\n", bi)
    }
}

Using this code, here's my output:

go      go1.18
path    [redacted]
mod     [redacted]     (devel)
dep     [redacted]        v1.2.3  
build   -compiler=gc
build   CGO_ENABLED=1
build   CGO_CFLAGS=
build   CGO_CPPFLAGS=
build   CGO_CXXFLAGS=
build   CGO_LDFLAGS=
build   GOARCH=amd64
build   GOOS=windows
build   GOAMD64=v1

I expected to see this included, but didn't:

build   vcs=git
build   vcs.revision=[sha]
build   vcs.time=2022-03-28T03:11:12Z
build   vcs.modified=true

I'm running the go command from the root directory of a git repo, and the repo has commits. The program I'm building is in a subdirectory of the repo.

I have tried a number of different variations for building the binary, but none of them worked:

go run client/main.go
go build -o client.exe client/main.go && ./client.exe
go build -o client.exe client/main.go && ./client.exe
go build -o client.exe -buildvcs=true client/main.go && ./client.exe

To be clear, the program builds and executes, but doesn't contain embedded VCS information.

I also tried using go version -m client.exe to see if that could read something that the binary couldn't read about itself, but the results were the same.

I'm using the first release of Go 1.18, so -buildvcs should still default to true as far as I know. I saw on the issue tracker that a future minor release will likely change the default to -buildvcs=auto.

As far as I can tell, both conditions listed in the release notes (go is invoked in a directory inside a git repo, and the main package is in the same repo) should both be satisfied when building from the project root. What might I be doing wrong?

1 Answers

I believe my issue was due to incorrect usage of the go run and go build commands. I was running and building against file patterns because I had originally tried go build client from the project root and gotten an error of "package is not in GOROOT", so I was building file patterns instead without understanding the difference (because it compiled and ran successfully).

I found that if I change directories into the subdirectory with the program I want to build (rather than build from the project root) the build command will embed the version information as expected.

e.g.:

cd client/ && go build

As @JimB pointed out in the comments, the go command is meant to operate on packages.

When building from the project root, this is the command I should have been using that will properly embed VCS version info inside the binary:

go build ./client

This behavior around relative path names is still confusing behavior to me, since I had expected go build client and go build ./client to be equivalent (which they are apparently not). Behavior around relative paths seems to be documented here: https://pkg.go.dev/cmd/go@go1.18#hdr-Relative_import_paths

Related