Manage multiple versions of the Go programming language
Installing Go
All versions of Go are available to download here: https://go.dev/dl/
The installation directory will be: /usr/local/go
.
Once you have Go installed, you can then use the go
command to either install go based tools/binaries or other versions of Go.
NOTE: Additionally, you can automate the install via a terminal using the following shell function (only tested on macOS):
# you can swap `ag` for `grep` if you prefer
alias golatest="curl -L https://github.com/golang/go/tags 2>&1 | ag '/golang/go/releases/tag/go[\w.]+' -o | cut -d '/' -f 6 | awk NR==1 | ag '\d.+' -o"
function go_install {
if [ -z "$1" ]; then
echo USAGE: go_install 1.18.1 OR go_install \$\(golatest\)
return
fi
v=$1
osname=$(uname -s | tr '[:upper:]' '[:lower:]')
hardware=$(uname -m)
mkdir -p ~/goversions
if ! test -f "~/goversions/go$v.$osname-$hardware.pkg"; then
printf "\nDownloading %s\n\n" "go$v.$osname-$hardware"
curl -L -o ~/goversions/go$v.$osname-$hardware.pkg https://go.dev/dl/go$v.$osname-$hardware.pkg
fi
echo ""
sudo rm -rf /usr/local/go; sudo installer -pkg ~/goversions/go$v.$osname-$hardware.pkg -target /usr/local/
clear
go version
}
Installing binaries
As of version go 1.16 go install
is now responsible only for installing binaries, not modifying a go.mod
file (that’s what go get
is for).
go install example.com/cmd@v1.0.0
go install example.com/cmd@latest
NOTE: See reference documentation.
Installing different go versions
The following is the ‘official’ approach…
NOTE: See reference documentation.
go install golang.org/dl/go1.18@latest
go1.18 download
go1.18 version # go version go1.18 darwin/amd64
alias go=go1.18
If you want a simple binary overwrite of the global go
command (for example, an alias
doesn’t work with Makefiles that reference go
because make targets run in a subshell):
go install golang.org/dl/go1.18@latest
go1.18 download
sudo cp $(which go1.18) $(which go)
NOTE: This requires
sudo
as it’s copying into/usr/local/...
.
If you want the latest ’tip’ release (and maybe with additional/unreleased features, at the time of writing that might have included something like ‘fuzzing’ which was made available in go1.18
):
go install golang.org/dl/gotip
gotip download dev.fuzz # also download a dev/tip specific tool/feature
gotip test -fuzz=FuzzFoo
Basic switcher using go.mod
as reference
# This function identifies the go version specified in a project's go.mod
# It then attempts to switch to a binary of that version.
# If none exists it will instruct you how to download it.
#
# NOTE: Some tools, e.g. TinyGo, won't work with this approach because we're
# just replacing the go binary and the VERSION file, where the originally
# installed version of go will have things like CGO files that TinyGo will try
# to use and if those don't align with the version of the binary we've switched
# to, then it means TinyGo will fail to compile.
#
# In that scenario you're better off using the `go_install` shell function
# approach at the top of the page.
function go_version {
if [ -f "go.mod" ]; then
v=$(grep -E '^go \d.+$' ./go.mod | grep -oE '\d.+$')
if [[ ! $(go version | grep "go$v") ]]; then
echo ""
echo "About to switch go version to: $v"
if ! command -v "$HOME/go/bin/go$v" &> /dev/null
then
echo "run: go install golang.org/dl/go$v@latest && go$v download && sudo cp \$(which go$v) \$(which go)"
return
fi
sudo cp $(which go$v) $(which go)
echo -n go$v | sudo tee $(dirname $(dirname $(which go)))/VERSION > /dev/null
fi
fi
}
# To support the configuring our go environment we will override the cd
# command to call the go logic for checking the go version.
#
# NOTE: We use `command` and not `builtin` because the latter doesn't take into
# account anything available on the user's $PATH but also because it didn't
# work with the Starship prompt which seems to override cd also.
function cd {
command cd "$@"
RET=$?
go_version
return $RET
}
Unofficial: goenv
https://github.com/syndbg/goenv
The nice thing about goenv is that it lets you more easily automate a switch between projects using either GOENV_VERSION
or .go-version
(docs).
But before we wrap up... time (once again) for some self-promotion 🙊