go: cmd/go: git export-subst causes hash mismatches

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

1.11rc1

Does this issue reproduce with the latest release?

yeap

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

see below

What did you do?

These are the steps I did on three different machines. You can see the hash is different on the Macbook Pro vs the iMac and Linux machine. All of these operations were done in a new $GOPATH and newly created module. I originally ran into this issue when doing go mod tidy on the iMac machine after committing the go.sum from the Macbook Pro.

Linux Workstation:

$ go1.11rc1 version
go version go1.11rc1 linux/amd64
$ uname -a
Linux theia 4.15.0-32-generic #35-Ubuntu SMP Fri Aug 10 17:58:07 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ go1.11rc1 env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/pivotal/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/pivotal/workspace/repro-mod-issue/go"
GOPROXY=""
GORACE=""
GOROOT="/home/pivotal/sdk/go1.11rc1"
GOTMPDIR=""
GOTOOLDIR="/home/pivotal/sdk/go1.11rc1/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/pivotal/workspace/repro-mod-issue/mod/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 -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build539505302=/tmp/go-build -gno-record-gcc-switches"

$ go1.11rc1 get k8s.io/client-go@v0.0.0-20180709172653-0ec73abb067f
go: finding k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f
go: downloading k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f
go: finding k8s.io/client-go v8.0.0+incompatible
go: downloading k8s.io/client-go v8.0.0+incompatible
$ cat go.sum
k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f h1:0k3XNLIMLwDNdQdkviifMIGTGVAJSJYePselvFsqV8s=
k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/client-go v8.0.0+incompatible h1:2pUaSg2x6iEHr8cia6zmWhoCXG1EDG9TCx9s//Aq7HY=

iMac:

$ go version
go version go1.11rc1 darwin/amd64
$ uname -a
Darwin otis 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/pivotal/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/pivotal/workspace/repro-mod-issue/go"
GOPROXY=""
GORACE=""
GOROOT="/Users/pivotal/sdk/go1.11rc1"
GOTMPDIR=""
GOTOOLDIR="/Users/pivotal/sdk/go1.11rc1/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/pivotal/workspace/repro-mod-issue/mod/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/nl/f9hjjjhn0qq7lp917hnx05m00000gn/T/go-build367695573=/tmp/go-build -gno-record-gcc-switches -fno-common"

$ go get k8s.io/client-go@v0.0.0-20180709172653-0ec73abb067f
go: finding k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f
go: downloading k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f
go: finding k8s.io/client-go v8.0.0+incompatible
go: downloading k8s.io/client-go v8.0.0+incompatible
$ cat go.sum
k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f h1:0k3XNLIMLwDNdQdkviifMIGTGVAJSJYePselvFsqV8s=
k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/client-go v8.0.0+incompatible h1:2pUaSg2x6iEHr8cia6zmWhoCXG1EDG9TCx9s//Aq7HY=

Macbook Pro:

$ go version
go version go1.11rc1 darwin/amd64
$ uname -a
Darwin wat.local 17.6.0 Darwin Kernel Version 17.6.0: Tue May  8 15:22:16 PDT 2018; root:xnu-4570.61.1~1/RELEASE_X86_64 x86_64
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/jasonkeene/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/jasonkeene/projects/repro-mod-issue/go"
GOPROXY=""
GORACE=""
GOROOT="/Users/jasonkeene/sdk/go1.11rc1"
GOTMPDIR=""
GOTOOLDIR="/Users/jasonkeene/sdk/go1.11rc1/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/jasonkeene/projects/repro-mod-issue/mod/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/f2/8qjhqmss5ssb6ccx15bxvvl80000gn/T/go-build890262066=/tmp/go-build -gno-record-gcc-switches -fno-common"

$ go get k8s.io/client-go@v0.0.0-20180709172653-0ec73abb067f
go: finding k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f
go: downloading k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f
go: finding k8s.io/client-go v8.0.0+incompatible
go: downloading k8s.io/client-go v8.0.0+incompatible
$ cat go.sum
k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f h1:j4/k4PUx72J2958XS0i/rAn6JAaoi1v48mLEaY8QGzM=
k8s.io/client-go v0.0.0-20180709172653-0ec73abb067f/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/client-go v8.0.0+incompatible h1:7Zl+OVXn0bobcsi4NEZGdoQDTE9ij1zPMfM21+yqQsM=

What did you expect to see?

The hashes should match. This is the same git SHA for k8s.io/client-go and same pseudo-version.

What did you see instead?

The hashes were different, resulting in a failed go mod tidy and go mod verify.

One difference between the Macbook Pro and iMac/Linux is that I installed go1.11rc1 the day before on the Macbook Pro. The other two machines I installed go1.11rc1 today. I installed using go get golang.org/dl/go1.11rc1 on all three machines.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 19 (17 by maintainers)

Commits related to this issue

Most upvoted comments

I’m not sure export-subst is something that go modules should enable. Here is my reasoning:

export-subst is a git attribute that allows for replacing certain format strings when git archive is invoked. The result is source code that is different than what would be in the working directory of the repo. Something like this:

gitVersion   string = "v0.0.0-master+$Format:%h$"

is turned into this:

gitVersion   string = "v0.0.0-master+0ec73abb"

This seems like behaviour that is undesierable. If I run:

go get module@sha1

I would expect to get the exact same source code for that SHA1. Instead I get a mutated version of the source code. We have seen issues with the format strings not being consistent between git versions. Even something like the amount of objects located in the repo can change the results of export-subst.

The situation that I ran into was k8s.io/client-go populating version information into the source code. This string can be populated by the builder via ldflags. Alternatively, version information can be read from the binary with something like rsc.io/goversion. export-subst is not needed to get version information into the binary.

Possbile solutions:

Disable export-subst attribute

This can be achieved by adding the following to .git/info/attributes before doing the git archive:

* -export-subst

This disables the option for the whole repo. Adding the attribute in this way has the highest precedence and can not be overrode by attributes in .gitattributes files or global configuration. I have been working on a CL that does this.

Disable all export attributes

This would include the export-ignore attribute. This attribute ignores certain paths when creating the .zip. This can be done by adding the following to .git/info/attributes.

* -export-subst -export-ignore

To be clear, export-ignore would likely not cause the ziphash to be different but it would cause the contents of the zip file to be different from the source code that is in the repo.

Require a minimum version of git that is after the change to %h

This option is not valid as the format strings for export-subst change with variables outside of the git version.

Do nothing

This would require all git repos that currently have these features enabled (likely for valid reasons) to stop using these features if they want to get consistent ziphashes. Naturally, folks will not know to do this until they run into this issue, causing them to at best do the research to find why this is occuring or more likely just ignore validation warnings. Training users to ignore these warnings seems like a bad idea.

I think a decision needs to be made if modules should use the contents of the repo as they are or if modules should apply extra processing to the source code via git archive and whatever other features are in other version control systems.

I agree that for the sake of reproducibility and consistency we should use the source as it is checked out, not depend on a post-processing step that is both uncommon and undeterministic, so I’d favor * -export-subst -export-ignore. (And I believe this is a git misfeature we should opt out of.)

It’s a bit unfortunate that the GitHub-generated zip files will differ, but it’s my understanding that we don’t use those anymore?

I’m not sure that this is actually a problem for cmd/go to solve.

export-subst should be fine as long as the substitutions are deterministic, well-defined, and stable across platforms and git versions. If a particular repository has an export-subst configuration that is inherently not deterministic or not stable, that seems like an issue to file against the owner of that repository.

If the main source of instability is git’s abbreviation algorithm, is there some way to specify abbreviation parameters explicitly, or to disable abbreviation altogether?