I think it's important to separate out the steps here a little bit more. Please correct me if I've gotten any of this wrong.
1. If we make go operations not update go.mod automatically, we need a clear way to say "fix up go.mod".
The obvious answer is "go get" (with no args), which almost works for that today.
That command does fix up go.mod, but it also does a build of the package, and for a package main does an install into a bin directory ($GOBIN / $GOPATH/bin / $HOME/go/bin).
That's an unfortunate overloading, so Jay suggests maybe it would make sense to do a one-time breaking of command lines and make get stop installing binaries ever.
Then "go get" (with no args) is unambiguously the "fix up go.mod" command, and more generally "go get" only ever modifies go.mod; it does not build and does not install anything.
2. If we stop making "go get" install to bin directories, then we should double-check:
is "go get -b" still the right spelling for the "isolated install of binary" operation?
Jay suggests maybe instead we introduce "go install path@version" to mean what we had been calling "go get -b path@version".
3. Marwan suggests maybe when path is not a relative path, "go install path" can mean what we had been calling "go get -b path@latest".
4. Paul suggests perhaps "go install -g path@version" would be the new spelling of "go get -b path@version", with "go install -g path" meaning "go get -b path@latest".
Having done that, a few thoughts.
Regarding (3), I would be reluctant to start changing the behavior of go commands based on the form used to name a package.
If I'm in the root directory of module m containing a foo subdirectory, then I really expect these command pairs to do the same things:
go test ./foo
go list ./foo
go build ./foo
go install ./foo
It would be very strange for that last one to mean "m/foo@latest". Same thing if we're talking about dependencies in other modules known to go.mod.
It would be weird for "go test my/dep/foo" to test the version implied by go.mod but "go install my/dep/foo" implicitly means @latest.
Redefining the behavior of existing "go install" commands seems to me unwise.
I don't see any way to special case "go install path" without introducing some very sharp jagged edges in the command-line behavior.
In particular, today it's always the case that "go anything path" and "go anything $(go list path)" do the same thing,
except for "go get", whose job is basically to break that rule.
I would be reluctant to break that rule in other commands, especially "go install".
On the other hand, "go install path@version" is not valid today and exists on a separate syntactic plane from these other commands,
so there's no breakage, nor are there jagged egdges with the existing commands.
We already allow "go list -m path@version" (naming a module).
If we add "go install path@version", we should probably also add "go list path@version" (naming a package).
Regarding (4), the flag -g ends up mostly redundant compared to having the flag-free "go install path@version".
The one time it is not is "go install -g path", which would otherwise have to be written "go install path@latest".
At that point the difference between "go install path" and "go install -g path" is "-g means latest version".
(I'm oversimplifying, but so will users who don't understand all these details.)
The argument for both (3) and (4) over (2) seems to be to shorten the "go install path@latest"
down to something where you needn't type the seven characters "@latest".
But comparing "go install path@latest" to "go install -g path",
I appreciate how much the former makes clear that the specific version is time-dependent.
To the extent that blindly grabbing the latest version of something
is a non-reproducible and somewhat risky operation, it's nice to have that more clearly spelled out.
One more thing that occurred to me as I wrote this: as far as (1) is concerned,
we could consider doing a gradual roll-out for that change, something like:
- Go 1.16:
- add go install path@version (or whatever the final spelling is)
- make go get path print a warning when path is a main package:
go get: in future Go versions, "go get" will not install binaries; use "go install" for that
- Go 1.17:
- go get stops printing the warning & stops installing the binary
Go 1.16 (in this example) would serve as a transition period when both the old and new
"get me a binary" commands work, so that people have a six-month window
to learn the new commands and update scripts instead of a flag day.
Best,
Russ