# gup: the manager for the binaries go install leaves in your GOBIN

> nao1215/gup updates, pins, lists, exports and migrates the command-line tools that `go install` scattered across your GOBIN. The interesting wrinkle is that even its prebuilt package still needs a Go toolchain, because gup shells out to the go command to do the work.

**nao1215/gup** — Fast manager for Go-installed binaries in $GOBIN: update, export/import, and migrate toolsets across machines

- Repository: https://github.com/nao1215/gup
- Website: https://nao1215.github.io/gup/
- Stars: 608 · Forks: 28
- Language: Go
- License: Apache-2.0
- Published: 2026-09-14 · Updated: 2026-09-14 · Language: en
- Canonical page: https://hysenlabs.com/projects/nao1215-gup

## go install writes to GOBIN and never looks back

The problem statement is one sentence long. `go install` puts each program in `$GOBIN`, which is `$GOPATH/bin`, and then never updates it again, keeps no manifest of what it installed, and gives you no way to hold a tool at a version you depend on.

gup is built around filling exactly those three gaps. It brings the whole set up to date in parallel, pins selected tools to exact versions, and adds the management commands `go install` lacks: `list` and `check` for what is installed, `remove` for binaries, `export` and `import` for moving the set to another machine, and `migrate` for a new `$GOBIN`. It runs on Windows, macOS and Linux, and the documentation lives separately at nao1215.github.io/gup. Since the tool calls the go command internally to reinstall a package, a Go installation is required even when you did not build gup from source.

## Seven package managers, two different payloads

gup is in homebrew-core, the winget community repository, the mise and aqua registries, nixpkgs and the AUR, in addition to `go install` and the release page packages. What differs between them is whether you compile gup or download a finished binary.

`go install` compiles it, and needs Go 1.26 or newer:

```
go install github.com/nao1215/gup@latest
```

Homebrew has two answers. `brew install gup` pulls from homebrew-core and needs no tap. `brew install nao1215/tap/gup` uses the GoReleaser-built formula in the author's own tap and installs the prebuilt release binary instead of building from source. On Windows it is `winget install --id nao1215.gup`; mise is `mise use -g gup@latest`; aqua adds it with `aqua g -i nao1215/gup`; and nixpkgs carries it under a different name entirely, `nix profile install nixpkgs#gogup`. Arch users get two community packages: `gup` builds from source, `gup-bin` installs the release binary.

## Even the prebuilt package needs Go on the machine

The release page carries packages in .deb, .rpm and .apk formats for amd64 and arm64, plus .tar.gz archives for Linux and macOS and .zip archives for Windows. Installing one looks like any other system package:

```shell
# Debian, Ubuntu
$ sudo dpkg -i gup_1.8.1_linux_amd64.deb

# Fedora, RHEL, openSUSE
$ sudo rpm -Uvh gup_1.8.1_linux_amd64.rpm

# Alpine Linux
$ sudo apk add --allow-untrusted gup_1.8.1_linux_amd64.apk
```

Swap `1.8.1` for the version you downloaded and `amd64` for `arm64` where that is what you have. The packages also drop in bash, fish and zsh completion files, which the archive-only routes do not do for you.

The catch is the sentence right below that list: the gup command uses the go command internally, so a golang installation is required. A machine with no Go toolchain cannot use gup even with a signed, checksummed, provenance-attested binary in hand.

## Every release ships checksums, an SBOM, and provenance

Each release carries supply-chain metadata, and verifying it is a documented step rather than an option. `checksums.txt` is signed with cosign in keyless mode, producing `checksums.txt.sigstore.json`, and an SPDX Software Bill of Materials is attached to every release archive. Build provenance is attested through GitHub OIDC and also attached as `multiple.intoto.jsonl`.

The checksum path takes two commands, the first proving the signature and the second checking your archive against the file it signs:

```shell
cosign verify-blob \
  --bundle checksums.txt.sigstore.json \
  --certificate-identity-regexp 'https://github.com/nao1215/gup/\.github/workflows/release\.yml@refs/tags/.*' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  checksums.txt
sha256sum --check --ignore-missing checksums.txt
```

Provenance has two equivalent routes: `gh attestation verify` with the GitHub CLI, or downloading `multiple.intoto.jsonl` and running slsa-verifier against the Sigstore transparency log.

The certificate identity in that block is pinned to the release workflow path and the issuer is pinned to GitHub's token endpoint, so a signature from some other workflow or some other issuer does not satisfy the check.

## update takes a name list, and exclude is comma separated

`gup update` with no arguments updates everything under `$GOBIN` in parallel. Naming binaries narrows it, and the output shows both a real upgrade and two tools that were already current:

```shell
$ gup update subaru gup ubume
update binary under $GOPATH/bin or $GOBIN
[1/3] github.com/nao1215/gup (v0.7.0 to v0.7.1, go1.20.1 to go1.22.4)
[2/3] github.com/nao1215/subaru (Already up-to-date: v1.0.2 / go1.22.4)
[3/3] github.com/nao1215/ubume/cmd/ubume (Already up-to-date: v1.4.1 / go1.22.4)
```

The exclusion list is comma separated with no spaces and takes `--exclude` or `-e`, and it combines with `--dry-run`. A name that is not installed is ignored, which is the point: the same list works on a machine where you have not installed everything yet. If a name looks like a typo of something that is installed, gup prints a did you mean warning rather than silently doing nothing.

## Per binary update source falls back to master only when main is missing

Most tools publish tagged releases, but some are developed on a branch and should be tracked there instead. gup lets you choose per binary: `--main` (or `-m`) updates by `@main`, `--master` updates by `@master`, and `--latest` updates by `@latest`.

The fallback rule is narrow and worth knowing. The `@main` to `@master` fallback applies only when the repository has no `main` branch at all. A project with both branches stays on `main`, so `-m` cannot silently drag you onto a legacy branch. Build, network, authentication, timeout and cancellation failures are reported per binary rather than aborting the whole run, which matters when you are updating twenty tools at once.

This is the switch to reach for when a tool publishes no tagged release, or when its newest tag sits months behind the branch it actually develops on. It composes with pinning rather than replacing it: one binary tracks a branch, another stays frozen at a version you depend on.

## The bench target compares gup against go-global-update

The Makefile carries the project's own answer to why you would need a manager at all. `bench-docs` measures gup against go-global-update and against a plain `go install` loop, then rewrites the comparison in `bench/README.md`. Running it needs himorime on your PATH; `bench-compare` runs the same suite against the working tree with `BASE=main`, which is how a change gets compared before it lands.

The rest of the build is conventional but unusually thorough for a single-binary tool. `e2e` runs offline end-to-end tests against the real CLI and needs atago. `coverage` combines unit and self-hosted end-to-end coverage through `scripts/coverage.sh`. `website` builds the documentation site into `website/public` and needs hugo, which is why the tree carries `website/`, `doc/`, `doc_sync_test.go` and a `release_test.go`.

## The Go floor is 1.26 and the macOS floor is 13 Ventura

The requirements moved with the toolchain. Unit tests run on Go 1.26 and 1.27, building from source needs Go 1.26 or newer, and go.mod declares `go 1.26.0`. The release binaries are built with the latest Go 1.27 patch release, which is what sets the macOS floor at Ventura or newer.

That floor is why an older Go installation is told to take a prebuilt release binary or a package instead. Three releases shipped inside four days: v1.10.1 on 2026-09-25, v1.10.2 on 2026-09-26, and v1.10.3 on 2026-09-28, with the last push to main on the same day as the newest tag. The project is Apache-2.0 licensed, which is what lets the tap formula, the AUR packages and the distro packages exist independently.

## Conclusion

Reach for gup when your GOBIN has become a pile of unversioned binaries and you want parallel updates, pinning, or a toolset you can reproduce on another machine. Pass if you are happy with go install and reinstall by hand, or if you cannot install Go, since gup calls the go command internally and a prebuilt package does not remove that dependency. Before trusting a downloaded archive, verify it against the signed checksums or the provenance attestation rather than the file name.

## FAQ

### What does gup do that go install does not?

go install places a binary in $GOBIN and never updates it again, keeping no manifest. gup updates the whole set in parallel, pins selected tools to exact versions, and adds list, check, remove, export, import and migrate commands.

### Do I need Go installed to use the gup binary?

Yes. The gup command uses the go command internally, so a golang installation is required even when you install a prebuilt package. Building gup from source additionally needs Go 1.26 or newer.

### How do I stop gup update from touching some tools?

Pass them to --exclude, or -e, separated by commas without spaces, which also works together with --dry-run. A name that is not installed is ignored, so one list can be shared between machines, and a name that looks like a typo of an installed binary produces a did you mean warning.

### How do I verify a gup release download?

Verify the cosign keyless signature on checksums.txt, then check the archive with sha256sum. Provenance can be checked with gh attestation verify, or with slsa-verifier against the attached multiple.intoto.jsonl. Each release also carries an SPDX SBOM.

### Which package managers ship gup?

homebrew-core, the winget community repository, the mise and aqua registries, nixpkgs under the name gogup, and two Arch packages where gup builds from source and gup-bin takes the release binary. go install and the release page packages are the other routes.

## Sources

- [License: Apache-2.0](https://github.com/nao1215/gup/blob/main/LICENSE)
- [nao1215/gup on GitHub](https://github.com/nao1215/gup)
- [Project website](https://nao1215.github.io/gup/)
- [README](https://github.com/nao1215/gup/blob/main/README.md)
- [Releases](https://github.com/nao1215/gup/releases)

---

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