I'm using Go modules in my project and in my build system (e.g. Travis CI) I'm downloading a command-line utility (written in Go) with go get
to assist with my build process, e.g.:
go get github.com/mitchellh/gox
However, this go get
causes the file to be added to my go.mod
file. This is contaminating the build environment, causing it to be "dirty" (since there are changes to some files tracked in git, in this case go.mod and go.sum), and I use git describe --always --dirty --tag
to describe my build, which shows up as "dirty".
Is there a way to "go get" a binary just to download it, without adding it to the go.mod/go.sum?
I've tried setting GOPATH to somewhere else, even then, go get
updates the go.mod/go.sum to add this as an // indirect
dependency.
dir="$(mktemp -d)"; \
env GOPATH="$dir" go get github.com/mitchellh/gox && \
mv "$dir/bin/gox" "$(go env GOPATH)"/bin/gox
Hopefully in Go 1.14 there will be a new flag for
go get
that does exactly what you are asking. This is tracked in issue #30515 "cmd/go: offer a consistent global install command".Prior to that, you have a few different options.
Go 1.12 and 1.13: change directory
If you are using Go 1.12 or later, the simplest solution is probably to move outside your current module to a directory without a
go.mod
prior to doing thego get
, such as:Go 1.11, 1.12, 1.13+: gobin
gobin is a module-aware command to install or run binaries that provides additional flexibility, including the ability to install without altering your current module's
go.mod
. See thegobin
README and FAQ for more details.Go 1.11: temporary module
If you are using Go 1.11 with modules, the first step is probably to upgrade to Go 1.12 or 1.13 given there are many improvements in modules. If you are required to use Go 1.11 and want to use the
@version
syntax without updating your current module'sgo.mod
, then one approach is to create a temporary module:This is because in Go 1.11, you can't use the
@version
syntax unless you are in a module, which was relaxed in Go 1.12. This approach has been automated by a simple shell script by @rogpeppe.Additional Details
In general, the
go
command in module-module always determines what module it is "in", which is based on the current working directory when you invoke thego
command. (You could make an analogy to howmake
without any args will look for a makefile in the current working directory, or how historicallygo build
without any args will build the current working directory, etc.).With modules,
go get
looks for ago.mod
file in the current working directory or any of its parents, andgo get
will use the constraints listed in anygo.mod
as part of solving for versions, as well as update thego.mod
if needed based on doing thego get
. That is why yourgo.mod
file is updated if you rungo get
from within an existing module.On the other hand, starting with Go 1.12, if you are in a directory that is not part of any module (that is, the directory does not have a
go.mod
, nor do any of its parents), then there is nogo.mod
to update, but thego
command is still able to operate in module mode and use the@version
syntax.From the Go 1.12 release notes:
Per
go help build
: