Use go mod to manage modules dependency and version
Module
Go has included support for versioned modules as proposed here - https://golang.org/design/24301-versioned-go since 1.11. The initial prototype vgo was announced - https://research.swtch.com/vgo in February 2018. In July 2018, versioned modules landed in the main Go repository.
Since Go 1.14 - https://golang.org/doc/go1.14, module support is considered ready for production use, and all users are encouraged to migrate to modules from other dependency management systems. If you are unable to migrate due to a problem in the Go toolchain, please ensure that the problem has an open issue - https://github.com/golang/go/wiki/Modules#github-issues filed. (If the issue is not on the Go1.16 milestone, please comment on why it prevents you from migrating so it can be prioritized appropriately). You can also provide an experience report - https://github.com/golang/go/wiki/ExperienceReports for more detailed feedback.
A module is a collection of related Go packages that are versioned together as a single unit.
Modules record precise dependency requirements and create reproducible builds.
Most often, a version control repository contains exactly one module defined in the repository root. (Multiple modules - https://github.com/golang/go/wiki/Modules#faqs–multi-module-repositories are supported in a single repository, but typically that would result in more work on an on-going basis than a single module per repository).
Summarizing the relationship between repositories, modules, and packages:
-
A repository contains one or more Go modules.
-
Each module contains one or more Go packages.
-
Each package consists of one or more Go source files in a single directory.
Modules must be semantically versioned according to semver - https://semver.org/, usually in the form v(major).(minor).(patch)
, such as v0.1.0
, v1.2.3
, or v1.5.0-rc.1
. The leading v
is required. If using Git, tag released commits with their versions. Public and private module repositories and proxies are becoming available (see FAQ - https://github.com/golang/go/wiki/Modules#are-there-always-on-module-repositories-and-enterprise-proxies below).
go.mod
A module is defined by a tree of Go source files with a go.mod
file in the tree’s root directory. Module source code may be located outside of GOPATH
. There are four directives: module
, require
, replace
, exclude
.
Here is an example go.mod file defining the module github.com/my/thing
:
1 | module github.com/my/thing |
A module declares its identity in its go.mod
via the module
directive, which provides the module path. The import
paths for all packages in a module share the module path as a common prefix. The module path and the relative path from the go.mod
to a package’s directory together determine a package’s import path.
For example, if you are creating a module for a repository github.com/user/mymod
that will contain two packages with import paths github.com/user/mymod/foo
and github.com/user/mymod/bar
, then the first line in your go.mod
file typically would declare your module path as module github.com/user/mymod
, and the corresponding on-disk structure could be:
1 | mymod |
In Go source code, packages are imported using the full path including the module path. For example, if in our example above, we declared the module identity in go.mod
as module github.com/user/mymod
, a consumer could do:
1 | import "github.com/user/mymod/bar" |
This imports package bar from the module github.com/user/mymod
.
exclude
and replace
directives only operate on the current (“main
”) module. exclude
and replace
directives in modules other than the main module are ignored when building the main module. The replace
and exclude
statements, therefore, allow the main module complete control over its own build, without also being subject to complete control by dependencies. (See FAQ - https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive below for a discussion of when to use a replace directive).
Usage
1 | mkdir -p go-mod-example |
go mod init
The go mod init
command initializes and writes a new go.mod
file in the current directory, in effect creating a new module rooted at the current directory. The go.mod
file must not already exist.
init accepts one optional argument, the module path for the new module. See Module paths for instructions on choosing a module path. If the module path argument is omitted, init will attempt to infer the module path using import comments in .go
files, vendoring tool configuration files, and the current directory (if in GOPATH).
Usage:
1 | go mod init [module-path] |
Example:
Initialize a new module:
You can replace cloudolife.com/examples/go-mod-example
with your preferred content.
1 | go mod init cloudolife.com/examples/go-mod-example |
Write your code:
1 | cat <<EOF > hello.go |
go mod tidy
Usage:
1 | go mod tidy [-e] [-v] |
go mod tidy
ensures that the go.mod
file matches the source code in the module. It adds any missing module requirements necessary to build the current module’s packages and dependencies, and it removes requirements on modules that don’t provide any relevant packages. It also adds any missing entries to go.sum
and removes unnecessary entries.
Build and run:
1 | go build -o hello |
The go.mod file was updated to include explicit versions for your dependencies, where v1.5.2
here is a semver tag:
1 | cat go.mod |
go mod vendor
Usage:
1 | go mod vendor [-e] [-v] |
The go mod vendor
command constructs a directory named vendor
in the main module’s root directory that contains copies of all packages needed to support builds and tests of packages in the main module. Packages that are only imported by tests of packages outside the main module are not included. As with go mod tidy and other module commands, build constraints except for ignore are not considered when constructing the vendor directory.
When vendoring is enabled, the go command will load packages from the vendor directory instead of downloading modules from their sources into the module cache and using packages those downloaded copies. See Vendoring for more information.
Daily Workflow
Note there was no go get required in the example above.
Your typical day-to-day workflow can be:
-
Add
import
statements to your.go
code as needed. -
Standard commands like
go build
orgo test
will automatically add new dependencies as needed to satisfy imports (updatinggo.mod
and downloading the new dependencies). -
When needed, more specific versions of dependencies can be chosen with commands such as
go get [email protected]
,go get foo@master
(foo@default with mercurial),go get foo@e3702bed2
, or by editinggo.mod
directly.
A brief tour of other common functionality you might use:
-
go list -m all
— View final versions that will be used in a build for all direct and indirect dependencies (details) -
go list -u -m all
— View available minor and patch upgrades for all direct and indirect dependencies (details) -
go get -u ./...
or goget -u=patch ./...
(from module root directory) — Update all direct and indirect dependencies to latest minor or patch upgrades (pre-releases are ignored) (details) -
go build ./...
or gotest ./...
(from module root directory) — Build or test all packages in the module (details) -
go mod tidy
— Prune any no-longer-needed dependencies from go.mod and add any dependencies needed for other combinations of OS, architecture, and build tags (details) -
replace
directive orgohack
— Use a fork, local copy or exact version of a dependency (details) -
go mod vendor
— Optional step to create a vendor directory (details)
Referecens
[1] Modules · golang/go Wiki · GitHub - https://github.com/golang/go/wiki/Modules
[2] Go Modules Reference - The Go Programming Language - https://golang.org/ref/mod
[3] Using Go Modules - The Go Blog - https://blog.golang.org/using-go-modules
Semantic Versioning 2.0.0 | Semantic Versioning - https://semver.org/