go mod: модули, версии, replace и vendor
Модуль — набор пакетов с go.mod; его module path одновременно является импортным префиксом. Команда go строит минимальную версию (MVS): для каждого модуля выбирается наибольшая явно требуемая версия, а не «последняя вообще».
Зачем это на интервью
Проверяется умение безопасно обновлять зависимости, объяснить совместимость и расследовать различие локальной и CI-сборок.
Минимум для E4
- Создать модуль:
go mod init example.com/acme/service. - Понимать назначение
go.mod(требования) иgo.sum(проверяемые хеши модулей). - После изменения импортов запускать
go mod tidy, затем проверятьgo test ./.... - Знать, что
replaceлокален для главного модуля и не передаётся потребителям библиотеки.
go mod init example.com/acme/service
go get example.com/lib@v1.4.2
go mod tidy
go list -m all
go mod graph
go mod why -m example.com/lib
go mod verifyУглубление для E5/Senior
Minimal Version Selection и обновления
MVS даёт повторяемый выбор для зафиксированного go.mod, но транзитивные зависимости всё ещё могут влиять на итоговый граф. Перед обновлением смотрят changelog, лицензии, advisory, go mod graph и integration-тесты. go get module@version меняет требования; go mod tidy удаляет неиспользуемые и добавляет требуемые записи по пакетам, тестам и build tags главного модуля.
Semantic Import Versioning
Для v0 и v1 путь обычно example.com/lib. Начиная с v2 major-версия входит в import path: example.com/lib/v2. Это позволяет v1 и v2 сосуществовать, но требует миграции импортов. Тег v2.0.0 без суффикса /v2 в module-директиве не делает модуль корректной v2-библиотекой.
import "example.com/lib/v2"replace, exclude и vendor
replace example.com/lib => ../lib полезен для локальной разработки или временного fork; его нельзя считать механизмом доставки зависимости пользователям. exclude запрещает конкретную версию и применяется осторожно: лучше понять, почему она вошла в граф. go mod vendor копирует нужные исходники в vendor/; go build -mod=vendor ./... использует их. Для Go 1.14+ при согласованном vendor-каталоге команда может выбрать его автоматически, поэтому после обновления запускают go mod vendor и коммитят изменения намеренно.
Ключевые понятия
| Термин | Значение |
|---|---|
| module path | канонический путь модуля и префикс импорта |
| MVS | выбор максимальной требуемой версии каждого модуля |
go.sum | checksums скачанных модульных содержимых, не lockfile |
| SIV | major v2+ в import path |
| vendor | снимок исходников зависимостей для сборки |
Типовые вопросы
- Почему
go.sumнужно коммитить?- Он фиксирует проверяемые хеши и позволяет обнаружить подмену/неожиданное содержимое; это не секрет.
- Как узнать, кто принёс зависимость?
go mod why -m moduleпоказывает путь использования,go mod graph— рёбра графа.
- Что делает
go mod tidy?- Синхронизирует require/sum с пакетами главного модуля; его вывод надо ревьюить как изменение зависимостей.
- Почему v2 требует
/v2?- Это часть Semantic Import Versioning, различающая несовместимые API на уровне импортов.
- Когда оправдан vendor?
- Когда политика или изолированная сборка требует исходников зависимостей в репозитории; он добавляет объём и требует синхронизации.
Практика
- Создайте модуль, добавьте прямую и транзитивную зависимость. Готово: объяснены строки
go.mod, выводыwhyиgraph,verifyпроходит. - Смоделируйте миграцию v1→v2. Готово: module path, тег и все импорты согласованы; обе major-версии объяснены.
- Сделайте vendor-снимок. Готово:
go mod vendor,go test -mod=vendor ./...и обычный тест проходят после чистого checkout.
Частые ошибки и ловушки
- Удалять
go.sum, чтобы «починить» зависимость, не понимая причины изменения. - Коммитить
replace ../localв библиотеку как будто он влияет на потребителей. - Помечать breaking API тегом
v1.xили забывать/v2. - Обновлять десятки модулей без тестов и review графа.
Связанные темы
Инструменты Go · Delivery · Тестирование