Go: cmd/go: Leave pinned version as a comment when dependency is incompatible with go modules

Created on 21 Mar 2019  Â·  7Comments  Â·  Source: golang/go

What version of Go are you using (go version)?

go version go1.12.1 darwin/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output

GOARCH="amd64"
GOBIN="/Users/egreer200/go/bin"
GOCACHE="/Users/egreer200/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/egreer200/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/Cellar/go/1.12.1/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.12.1/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/egreer200/git/kuberhealthy/pkg/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/7h/qd9xrbq10lb03g4lkqcl_cdr0000gp/T/go-build290178356=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I pinned a dependency (k8s.io/apimachinery kubernetes-1.11.7) in go.mod and ran go build.

What did you expect to see?

I expected my pinned version to be in the go.mod file.

What did you see instead?

The go.mod file left behind a unique hash that no longer shows what I asked it to pin (k8s.io/apimachinery v0.0.0-20190118094746-1525e4dadd2d). Go should at least leave a note indicating what human-readable version is pinned with the module hash format. This leads developers (at first use) to think that the program overrode their version pinning request.

I understand this is expected behavior and that the hash indicates a static version to pull in, but I would like to see some hints left behind so people know what tag it _really_ is. For example:

What the dev inputs:

require k8s.io/apimachinery kubernetes-1.11.7

What the dev sees after' running go get:

require (
    k8s.io/apimachinery v0.0.0-20190118094746-1525e4dadd2d
)

What I would like to see (as a dev):

require (
    k8s.io/apimachinery v0.0.0-20190118094746-1525e4dadd2d // kubernetes-1.11.7
)
FeatureRequest FrozenDueToAge GoCommand modules

Most helpful comment

Seems reasonable. go get could also write these comments if a particular branch is requested.

Not sure if this will happen for 1.13, given how much other stuff needs to go in, but it would be nice to have.

All 7 comments

@bcmills @jayconrod

Seems reasonable. go get could also write these comments if a particular branch is requested.

Not sure if this will happen for 1.13, given how much other stuff needs to go in, but it would be nice to have.

go.mod does not “pin” dependencies: it specifies minimums.

That said, I think this is a duplicate of #25898. Please reopen if you disagree.

Thanks for the reply. I think that issue is different, but would accomplish the same thing.

But, if you see this thread again, can you briefly explain what you mean by go.mod not pinning dependencies?

I see a line in go.mod like this: k8s.io/apimachinery v0.0.0-20190118094746-1525e4dadd2d and commands like go get foo@e3702bed2 seem to specify an exact revision.

go.mod doesn't pin dependencies, in that the versions specified in your go.mod file are treated as minimum versions — not exact constraints — if and when your module is used as a dependency of some other module.

(If your module is always the main module when you build it, then the “minimum version” is functionally equivalent to “pinning”, but we try not to make that assumption in discussions and documentation.)

Whoa. Does this mean that an upstream dependency can release a new version that will cause my builds to fail? Does go automatically try older versions to see if one works in that case? How would one "pin" an exact upstream version if needed? Is vendoring the only option?

Thanks for the reply!

Does this mean that an upstream dependency can release a new version that will cause my builds to fail?

Nope: the version selected for a given go.mod file is stable over time — it's just not “pinned”, in the sense that if someone else uses your module as a dependency, your module's requirements will set a minimum (but not a maximum) on the versions of modules that _they_ can require in conjunction.

(See https://research.swtch.com/vgo-mvs for details.)

Does go automatically try older versions to see if one works in that case?

The maximum of the minimum-versions explicitly listed in the module graph is always selected. The only time we try a different version is if we see an import statement that names a package that does not exist in the currently-active module versions.

How would one "pin" an exact upstream version if needed?

Generally you don't need to. You set your versions, and because the go command selects the minimum version that satisfies both your explicit requirements and those of your (transitive) dependencies, that selection remains stable over time.

Was this page helpful?
0 / 5 - 0 ratings