# g: a Go version manager that is one readable shell script

> g is an MIT licensed Go version manager written as a single POSIX shell script that installs official prebuilt Go archives as an unprivileged user, needs no shims and works across bash, zsh, fish and others, with a TUI that stays pipe-friendly. It suits a developer who wants version switching without a plugin ecosystem, and it is the wrong tool if you need to build Go from source or want a manager that also handles your module dependencies.

**stefanmaric/g** — Simple go version manager, gluten-free

- Repository: https://github.com/stefanmaric/g
- Stars: 1,089 · Forks: 55
- Language: Shell
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/stefanmaric-g

## The pitch is what other managers do not do

The README states the problem the tool exists to solve, that existing version managers often build Go from source, require a specific shell, pollute your environment with shims and functions, or bring a large plugin ecosystem you might not need. The design goal in response is to be as unobtrusive and portable as possible, with one readable shell script, official prebuilt Go archives, no privileged install, and a pair of idiomatic Go environment variables. The features list follows the same logic. Installation and version switching use official prebuilt archives, there is no privileged install and no sudo, the tool is a single portable POSIX script that works across common shells without shims, and it is transparent in the sense that g is a shell script you can inspect, copy and patch. The author notes the inspiration, tj/n, which he has contributed to and whose code he borrows.

## One line to install, and it edits your shell startup file

The README asks you to read the install script before running it, which is a better practice than most installers get credit for, and then gives two equivalent invocations.

```shell
curl -fsSL https://github.com/stefanmaric/g/releases/latest/download/install | sh
```

or with wget.

```shell
wget -qO- https://github.com/stefanmaric/g/releases/latest/download/install | sh
```

The installer downloads g to $GOPATH/bin/g, makes it executable, and updates your shell startup file with GOROOT, GOPATH and $GOPATH/bin on PATH. The defaults are the standard Go locations.

```shell
GOROOT=$HOME/.go
GOPATH=$HOME/go
```

$GOPATH/bin has to be on PATH because that is where g and the active go binary live, and the README says to restart your shell afterwards so the new environment is loaded. The installer supports bash, zsh, fish, ash, dash, csh and tcsh, and can configure more than one shell in a single run, with the arguments being the shell names.

## The installer takes flags for unattended and multi-shell setups

The installer options cover the cases that matter in practice. A -y flag skips all prompts and installs the latest Go version immediately.

```shell
curl -fsSL https://github.com/stefanmaric/g/releases/latest/download/install | sh -s -- -y
```

A single shell can be targeted by passing its name, and several at once.

```shell
curl -fsSL https://github.com/stefanmaric/g/releases/latest/download/install | sh -s -- fish bash zsh
```

The default locations can be changed by exporting GOROOT and GOPATH before running the installer, with the fish variant using set -gx instead of export.

```shell
export GOROOT=$HOME/.local/share/golang
export GOPATH=$HOME/go-projects
curl -fsSL https://github.com/stefanmaric/g/releases/latest/download/install | sh
```

There is also a manual installation path for people who would rather not pipe a remote script into a shell: set the variables in your shell init file, copy bin/g from the repository into a directory on your PATH, and make it executable with chmod +x.

## The command set covers install, switch, run and prune

The command reference in the README is compact and readable.

```text
Commands:
  g                         Open interactive UI with downloaded versions
  g install latest          Download and set the latest Go release
  g install <version>       Download and set Go <version>
  g download <version>      Download Go <version>
  g set <version>           Switch to Go <version>
  g run <version>           Run a given version of Go
  g which <version>         Output bin path for <version>
  g remove <version ...>    Remove the given version(s)
  g prune                   Remove all versions except the current version
  g list                    Output downloaded Go versions
  g list-all                Output all available remote Go versions
  g self-upgrade            Upgrade g to the latest version
  g help                    Display help information, same as g --help
```

Aliases are provided for the common ones, install also answering to use, download to fetch, run to exec, remove to rm or uninstall, list to ls and list-all to ls-remote. Running g with no command opens the interactive picker over the versions you have already downloaded. Two commands deserve a note. g run executes a given version without changing the active one, which is how a CI job or a one-off script uses a pinned toolchain. g prune removes every version except the current one.

## Colourful output that does not break a pipeline

The feature list describes a colourful and interactive TUI that is nevertheless safe to pipe and use in automated scripts, and the options section backs that up with the flags that make it possible. -q suppresses almost all output, -c forces colour off, and -y prevents prompts altogether. There are also overrides for the target, with -o for the operating system and -a for the architecture, and -u to include unstable versions in the listing, which is how beta and release candidate builds become visible. The tool also has g self-upgrade for updating itself, and -v prints the version of g rather than of Go.

## Mirrors are supported, and checksums are still verified

By default archives come from dl.google.com/go, and the --archive-url option points somewhere else for a single install.

```shell
g install latest --archive-url https://golang.google.cn/dl
```

A persistent default is set with an environment variable instead.

```shell
export G_GO_ARCHIVE_URL=https://golang.google.cn/dl
g install latest
```

The README is careful about what a mirror must be, noting that archive-only mirrors work as long as they serve the official Go archive filenames, with a mirror such as mirrors.aliyun.com/golang given as the example. The line that closes the section is the important one, that mirror downloads are still verified against the official Go checksum before extraction. So a mirror changes where the bytes come from, not whether they are checked.

## Shell tooling in the build, and a project that ships its own tests

The Makefile is a POSIX shell Makefile that fetches its own tooling into a .tmp directory. It downloads ShellCheck at v0.11.0, shfmt at 3.13.1, and sharness at v1.2.1, and the architecture substitution in the variables shows the care taken, with arm64 mapped to aarch64 for ShellCheck, x86_64 to amd64 for shfmt, and aarch64 back to arm64. The lint target runs ShellCheck and shfmt in diff mode over bin/ and mocks/, the format target rewrites with shfmt, and the test target loops over tests/*.t files running each under sharness. The repository root shows the shape, with bin/ holding the scripts, mocks/ holding test doubles, tests/ holding the .t files, a CHANGELOG.md, a CODE_OF_CONDUCT.md, a CONTRIBUTING.md and a Makefile. The default branch is next, and the release history shows 1.0.0 tagged on 2026-05-26 after 0.11.0 the same day, with 0.10.0 from 2023, and the last push was on 2026-05-26.

## Conclusion

g fits a developer who installs Go from official archives, wants to switch between versions without shims or a plugin framework, and is willing to read the tool that manages their toolchain, since the whole program is one script you can inspect and patch. It is a poor fit if you need to build a Go toolchain from source for a platform with no official archive, and a poor fit for a team standardising on a larger manager with a plugin ecosystem. Verify first that your platform has an official Go archive, since the tool downloads those archives rather than compiling, and note that the default branch is next with version 1.0.0 tagged in May 2026, so the released line and the branch you read may not be the same.

## FAQ

### What does g need to run?

macOS, Linux, BSD or WSL, a POSIX-compatible shell, either curl or wget, and one of sha256sum, shasum or openssl. The README notes you most likely already have all of them.

### How do I install the g Go version manager?

With curl -fsSL https://github.com/stefanmaric/g/releases/latest/download/install | sh, or the wget equivalent, after reading the install script as the README asks. The installer puts g in $GOPATH/bin and sets GOROOT, GOPATH and PATH in your shell startup file, and you need to restart your shell afterwards.

### Can g run a specific Go version without changing the active one?

Yes, g run <version> runs a given version of Go without switching the active one, and g which <version> outputs the binary path for a version. That is the form to use in CI jobs that need a pinned toolchain.

### Are downloads from a mirror still verified?

Yes. The README states that mirror downloads are still verified against the official Go checksum before extraction, and that archive-only mirrors work as long as they serve the official Go archive filenames.

## Sources

- [Issues](https://github.com/stefanmaric/g/issues)
- [License: MIT](https://github.com/stefanmaric/g/blob/next/LICENSE)
- [README](https://github.com/stefanmaric/g/blob/next/README.md)
- [Releases](https://github.com/stefanmaric/g/releases)
- [stefanmaric/g on GitHub](https://github.com/stefanmaric/g)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stefanmaric-g
