Avatar ·

В чем разница между `go get` и `go install` в Go?

Привет! Я недавно начал изучать Go и пытаюсь разобраться с управлением зависимостями и сборкой проектов. Я часто вижу использование команд `go get` и `go install`, но не совсем понимаю, в чем между ними разница. Например, я хочу установить утилиту `hey` для нагрузочного тестирования. В документации написано: `go get -u github.com/rakyll/hey` и `go install github.com/rakyll/hey@latest`. Обе команды вроде бы скачивают и устанавливают программу, но я заметил, что после `go get` бинарник появился в `$GOPATH/bin`, а после `go install` — тоже туда, но при этом в папке проекта появился файл `go.sum`. Я также пробовал использовать `go get` для добавления библиотеки в свой проект: `go get github.com/gin-gonic/gin`. После этого в `go.mod` появилась строка с зависимостью, а в `go.sum` — хеши. Но я читал, что в новых версиях Go (1.16+) `go get` не рекомендуется для установки бинарников, а только для управления зависимостями. Можете объяснить, в чем именно разница? Когда я должен использовать `go get`, а когда `go install`? И что изменилось в новых версиях Go? Приведите примеры, чтобы было понятно. <<>>

Основное различие между go get и go install

Ключевое различие в том, что go get управляет зависимостями (изменяет go.mod), а go install просто компилирует и устанавливает бинарный файл без изменения файлов модуля.

Исторический контекст и изменения в Go 1.16+

До Go 1.16 команда go get выполняла две функции одновременно:

  • Добавляла зависимость в go.mod
  • Компилировала и устанавливала бинарник (если пакет был main)

Начиная с Go 1.17 (и особенно с Go 1.18), поведение изменили:

  • go get — только для управления зависимостями. Он добавляет/обновляет/удаляет строки в go.mod и обновляет go.sum. Бинарники не устанавливаются.
  • go install — только для установки бинарников. Он компилирует пакет и помещает исполняемый файл в $GOPATH/bin (или $GOBIN). go.mod не изменяется.

Пример 1: Установка утилиты (бинарника)

Хотим установить hey для тестирования:

// ПРАВИЛЬНО (Go 1.16+):
go install github.com/rakyll/hey@latest

// НЕПРАВИЛЬНО (устарело):
go get -u github.com/rakyll/hey  // В новых версиях Go это не установит бинарник!

После go install бинарник появится в $GOPATH/bin/hey. Команда @latest указывает версию — это обязательный синтаксис для go install.

Пример 2: Добавление библиотеки в проект

Работаем в проекте с go.mod:

// Создаем проект
mkdir myapp && cd myapp
go mod init myapp

// Добавляем зависимость Gin
go get github.com/gin-gonic/gin

// После этого в go.mod появится:
// require github.com/gin-gonic/gin v1.9.1
// А в go.sum — хеши для проверки целостности

// Теперь можно импортировать в коде:
import "github.com/gin-gonic/gin"

Пример 3: Установка бинарника из текущего проекта

// Если в проекте есть cmd/myapp/main.go с package main:
go install ./cmd/myapp

// Бинарник myapp появится в $GOPATH/bin

Обратите внимание: путь указывается относительно текущего модуля, а не полный URL.

Когда что использовать?

  • go get — когда нужно добавить, обновить или удалить зависимость в go.mod вашего проекта. Например: go get github.com/sirupsen/logrus@v1.9.0
  • go install — когда хотите установить готовую программу (утилиту, CLI-инструмент) из любого репозитория. Например: go install golang.org/x/tools/gopls@latest
  • go build — когда нужно просто скомпилировать проект без установки бинарника в систему. Например: go build -o myapp .

Важные нюансы

  • При использовании go install с URL (например, go install github.com/user/repo@v1.0.0) Go автоматически загружает модуль во временную директорию, компилирует и помещает бинарник в $GOBIN. go.mod вашего текущего проекта не изменяется.
  • Если вы используете go install внутри папки проекта (без URL), то будет скомпилирован текущий модуль.
  • go get без указания версии (например, go get github.com/package) установит последнюю версию, но с учетом требований других зависимостей в go.mod.

В итоге: go get — для управления go.mod, go install — для установки бинарников. В новых версиях Go эти функции строго разделены.

<<>>

Если вам нужно быстро установить инструмент для разработки

Я часто использую такой подход: создаю отдельный модуль для установки утилит, чтобы не засорять рабочие проекты. Например:

// Создаем временную папку
mkdir ~/temp-tools && cd ~/temp-tools
go mod init temp-tools

// Устанавливаем нужные инструменты через go install
go install github.com/rakyll/hey@latest
go install github.com/go-delve/delve/cmd/dlv@latest
go install golang.org/x/tools/gopls@latest

// После установки можно удалить папку temp-tools
cd .. && rm -rf ~/temp-tools

Этот метод гарантирует, что вы не испортите go.mod вашего основного проекта случайными зависимостями. Бинарники при этом останутся в $GOPATH/bin.

Ещё один лайфхак: если вы хотите проверить, куда именно установится бинарник, выполните:

go env GOBIN  // если пусто, то используется GOPATH/bin

И не забудьте добавить $GOPATH/bin в переменную окружения PATH, чтобы можно было запускать установленные утилиты из любой папки.