cmd/go: 1.20 broke buildvcs inside bare Git repositories with worktrees
tie opened this issue · 7 comments
What version of Go are you using (go version)?
$ go version go version go1.20.2 linux/arm64
Does this issue reproduce with the latest release?
Yes, this issue was introduced in Go 1.20 release.
What operating system and processor architecture are you using (go env)?
go env Output
$ go env GO111MODULE="" GOARCH="arm64" GOBIN="" GOCACHE="/home/tie/.cache/go-build" GOENV="/home/tie/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="-trimpath" GOHOSTARCH="arm64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/tie/go/pkg/mod" GONOPROXY="go.pact.im/private" GONOSUMDB="go.pact.im/private" GOOS="linux" GOPATH="/home/tie/go" GOPRIVATE="go.pact.im/private" GOPROXY="https://proxy.golang.org,direct" GOROOT="/nix/store/hi9hs61z09yi1c9v5paw4273cbyhf51w-go-1.20.2/share/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/nix/store/hi9hs61z09yi1c9v5paw4273cbyhf51w-go-1.20.2/share/go/pkg/tool/linux_arm64" GOVCS="" GOVERSION="go1.20.2" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="0" GOMOD="/dev/null" GOWORK="" CGO_CFLAGS="-O2 -g" CGO_CPPFLAGS="" CGO_CXXFLAGS="-O2 -g" CGO_FFLAGS="-O2 -g" CGO_LDFLAGS="-O2 -g" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build711157649=/tmp/go-build -gno-record-gcc-switches"
What did you do?
go20-buildvcs-issue.sh
#!/bin/sh
set -eu
temp=$(mktemp -d)
cleanup() {
rm -r -f -- "$temp"
}
trap cleanup EXIT
cd "$temp"
cat >go.mod <<EOF
module test
EOF
cat >main.go <<EOF
package main
import "fmt"
func main() {
fmt.Println("OK")
}
EOF
(
mkdir source && cd source
git init --quiet
cp ../go.mod ../main.go .
git add go.mod main.go
git commit --quiet --message 'initial commit'
)
gobuild() {
go build -o out
go version -m out
./out && rm out
}
go version
(
echo && echo "Git repository"
git clone --quiet ./source good && cd good
gobuild
)
(
echo && echo "Git repository with nested worktree"
git clone --quiet ./source nested-worktree && cd nested-worktree
git worktree add --quiet nested && cd nested
gobuild
)
(
echo && echo "Bare Git repository with worktree"
git clone --quiet --bare ./source bare/.git && cd bare
git worktree add --quiet main && cd main
gobuild
)Go 1.19
$ nix shell nixpkgs#go_1_19 -c sh go20-buildvcs-issue.sh
go version go1.19.6 linux/arm64
Git repository
out: go1.19.6
path test
mod test (devel)
build -compiler=gc
build -trimpath=true
build CGO_ENABLED=0
build GOARCH=arm64
build GOOS=linux
build vcs=git
build vcs.revision=043649dd3ee451e187991c8ce7d54934b2d47cda
build vcs.time=2023-03-16T03:13:43Z
build vcs.modified=false
OK
Git repository with nested worktree
out: go1.19.6
path test
mod test (devel)
build -compiler=gc
build -trimpath=true
build CGO_ENABLED=0
build GOARCH=arm64
build GOOS=linux
build vcs=git
build vcs.revision=043649dd3ee451e187991c8ce7d54934b2d47cda
build vcs.time=2023-03-16T03:13:43Z
build vcs.modified=false
OK
Bare Git repository with worktree
out: go1.19.6
path test
mod test (devel)
build -compiler=gc
build -trimpath=true
build CGO_ENABLED=0
build GOARCH=arm64
build GOOS=linux
build vcs=git
build vcs.revision=043649dd3ee451e187991c8ce7d54934b2d47cda
build vcs.time=2023-03-16T03:13:43Z
build vcs.modified=false
OK
Go 1.20
$ nix shell nixpkgs#go_1_20 -c sh go20-buildvcs-issue.sh
go version go1.20.2 linux/arm64
Git repository
out: go1.20.2
path test
mod test (devel)
build -buildmode=exe
build -compiler=gc
build -trimpath=true
build CGO_ENABLED=0
build GOARCH=arm64
build GOOS=linux
build vcs=git
build vcs.revision=fc4846bf2f91ae1065294ddb0d1696e58a9cf850
build vcs.time=2023-03-16T03:17:37Z
build vcs.modified=false
OK
Git repository with nested worktree
out: go1.20.2
path test
mod test (devel)
build -buildmode=exe
build -compiler=gc
build -trimpath=true
build CGO_ENABLED=0
build GOARCH=arm64
build GOOS=linux
build vcs=git
build vcs.revision=fc4846bf2f91ae1065294ddb0d1696e58a9cf850
build vcs.time=2023-03-16T03:17:37Z
build vcs.modified=true
OK
Bare Git repository with worktree
error obtaining VCS status: exit status 128
Use -buildvcs=false to disable VCS stamping.
Notice that Go 1.19 works fine with this setup.
A shorter reproducer for this bug:
go20-buildvcs-issue.sh
#!/bin/sh
set -eu
temp=$(mktemp -d)
cleanup() {
rm -r -f -- "$temp"
}
trap cleanup EXIT
cd "$temp"
git init --quiet
echo -n 'module test' >go.mod
echo -n 'package main;func main(){}' >main.go
git add go.mod main.go
git commit --quiet --message 'initial commit'
git config core.bare true && rm go.mod main.go
git worktree add --quiet main && cd main
go build -o out
go version -m outAlso note that this is not an issue with Go version in Nixpkgs, the examples above use nix just to avoid installing different Go versions.
What did you expect to see?
All builds succeed.
What did you see instead?
Go 1.20 runs git status --porcelain outside of the Git work tree, the command fails with fatal: this operation must be run in a work tree error.
Seems to be introduced in bb39656 that added checks for file mode when searching for repository root.
For reference, in Git work trees, .git is a file containing gitdir: <path-to-root>/.git/worktrees/<name> (although the path is absolute by default, Git works with relative paths too).
https://github.com/git/git/blob/73876f4861cd3d187a4682290ab75c9dccadbc56/setup.c#L843-L866
I’m not really sure if bb39656 was the right way to fix the case in #53640, which had a broken Git repository in the first place (since only the submodule was copied to the Docker container without the Git directory).
Before this change, VCS stamping worked in perfectly valid Git repositories with gitdir link but did not in “broken” (i.e. where gitdir points to a non-existent Git directory). Now it just doesn’t work.
Oh, right, sorry for not looking up existing issues! I known that work trees are somewhat an advanced Git feature and are likely used by a minority of users, and since this wasn’t fixed yet I’ve assumed that nobody reported this issue 😅
Will the fix be eventually backported to 1.20 release?
Yes, this is a duplicate. And I would say we would backport the revert, given that it's a regression and the revert should be relatively harmless.