Wechat official account “Backend Advanced” focuses on back-end technology sharing: Java, Golang, WEB framework, distributed middleware, service governance and so on.

In Java projects, Maven and Gradle are very useful and rely on version management tools. However, Golang does not provide version management tools. We used to use Go Get to get dependencies that were potentially dangerous, because we weren’t sure if the latest version of dependencies would break the way our project used dependencies, i.e. the current project might not be compatible with the latest dependencies. Later, an official vendor mechanism was developed, which placed all the packages that the project depended on in this directory, but this did not manage the versions of dependencies well. Later, there was a quasi-official version management tool called Go DEp, which is a precursor to Go Modules. With the release of Go1.11, Golang brings a new feature to the module, a new dependency management system for Golang. Now that Go1.12 has been released, Go Modules are more stable, but they still haven’t been officially set as the default mechanism, so it’s a must. In addition to detailing the features and use of Go Modules, this article summarizes some of the “bugs” I’ve encountered along the way.

Create the module

  • Create a project

By default, $GOPATH does not support Go Mudules by default, we need to manually execute the following command in the project directory:

$ export GO111MODULE=on
Copy the code

This shows that Go is determined to use modules to kill $GOPATH.

To work with the Go Modules mechanism, we create a testmod package in a directory other than $GOPATH:

$ mkdir testmod
$ cd testmod

$ echo 'package testmod import "fmt" func SayHello(name string) string { return fmt.Sprintf("Hello, %s", name) }' >> testmod.go
Copy the code
  • Initialize module:
$ go mod init github.com/objcoding/testmod
go: creating new go.mod: module github.com/objcoding/testmod
Copy the code

The above command creates a go.mod file in the project, which initializes as follows:

module github.com/objcoding/testmod
Copy the code

At this point, our project has become a Module.

  • Push to the Github repository
$ git init
$ git add *
$ git commit -am "First commit"
$ git push -u origin master
Copy the code

Here I will also focus on the project dependency package reference address problem, which is small, but really annoying, so it must be said:

Before the introduction of Go Mudules, there were many packages within a project, and some packages depended on other packages within the project. If a project had a package whose address relative to Gopath was objcoding/mypackage, it could be referenced by other packages within the project:

import myproject/mypackage
Copy the code

But have you ever thought that when another project needs to reference some of the packages in your project, you need to download the dependencies remotely, and then you need to reference the repository address of the project, for example:

import github.com/objcoding/myproject/mypackage
Copy the code

The first line of the initialization content is the project dependency path, which is usually the repository address of the project. All the addresses that need to reference the project package are filled with this address. Whether it’s inter-internal references or external references, for example, goim’s internal package references:

Go. Mod module:

Internal package reference:

After the go Modules is enabled for your project, the reference package must have the same name as the first line of the Go mod file.

All dependencies are stored in the ${GOPATH}/ PKG /mod folder. You can also view dependencies at the bottom of the project:

If you don’t set the project to Go Modules in the Goland editor, you can set the project to go Modules as follows:

When checked, the Go Modules directory will appear in the External Libraries.

Version of the rules

Go Modules is a versioning dependency management system. The version must follow some rules. For example, the version number must follow the following format:

VX. Y.Z - pre. 0. Yyyymmddhhmmss - abcdefabcdef vX. 0.0 - yyyymmddhhmmss - abcdefabcdef vX. Y. (Z + 1) - 0. Yyyymmddhhmmss - abcdefabcdef vX.Y.ZCopy the code

Vx.y.z is the labeled version of our warehouse, that is, the go modules determines the version number according to the label of the warehouse, so when we release the version, we need to label the version number of our warehouse.

If there is no version tag, we need to find the time and hash value corresponding to commit.

Another important rule is that versions 0 and 1 should have different dependency paths. For example, v1.0.0 and v2.0.0 have different dependency paths. This version rule is described in more detail below.

The release

Now that we know the version rules for Go Modules, let’s release the version of the project:

$git tag v1.0.0 $git pushCopy the code

At this point, we should also create a v1 branch so that we can write code in other branches without affecting the V1.0.0 version:

$ git checkout -b v1
$ git push -u origin v1
Copy the code

The use of the module

Now let’s take the module we just made and use it to create a Gomodules project:

package main

import (
    "fmt"
    "github.com/objcoding/testmod"
)

func main(a) {
    fmt.Println(testmod.SayHello("Cheung Shing Fai"))}Copy the code

Previously we could get dependencies directly with the go get command, but for a Module project, this is far more interesting. Now we initialize the project as a Module project:

$ go mod init
Copy the code

The go build command will download the dependency package and add the dependency information to the go.mod file, and store the dependency version hash information in the go.sum file:

$go build go: finding github.com/objcoding/testmod v1.0.0 go: downloading github.com/objcoding/testmod v1.0.0Copy the code

At this point, the go.mod file will look like this:

module gomodules
require github.com/objcoding/testmod v1. 0. 0
Copy the code

The go.sum file contains the following contents:

github.com/objcoding/testmod v1. 0. 0 h1:fGa15gBXoqkG0BVkQGP9i5Pg2nt8nayFpHFf+GLiX6A=
github.com/objcoding/testmod v1. 0. 0/go.mod h1:LGpYEmOLZhLQC3JW88STU2Ja3rsfoGZmsidsHJhDNGU=
Copy the code

It should also be noted that sometimes we reference some packages of golang.org/x/, but find that the address is qian in the great Chinese Dynasty, but we programmers also give full play to the good tradition of diligence and learning, set goproxy mechanism in go Modules. If the go Modules is configured with the proxy, the dependency packages will be downloaded from the proxy first. Add the following content to /etc/profile:

export GOPROXY="https://goproxy.io"
Copy the code

Goproxy. IO Google official proxy address, of course, there are many excellent domestic third-party agents.

You can also set it in the Goland editor:

Upgraded version

Now let’s update the Testmod project:

$ cd gomodules
$ echo 'Package testmod import "FMT" func SayHello(name string) string {return FMT.Sprintf(" %s", name)}' >> testmod.go
Copy the code

I changed “Hello” to “Hello”, and we made this change in the v1 branch:

$ git commit -m "update testmod"Go $git tag v1.0.1 $git push --tags origin v1Copy the code

Now that our project has been upgraded to v1.0.1, we can obtain this version dependency in a number of ways. In GO 1.11, Go Get has many new features. We can directly obtain the v1.01 version dependency by using the following command:

$go get github.com/objcoding/[email protected]Copy the code

You can also use the go mod command:

$ go mod edit -require="github.com/objcoding/[email protected]"

$ go mod tidy
Copy the code

Go mod Edit-require takes the initiative to change the version numbers of dependencies in the go.md file and then updates the version with Go Mod Tidy, a godlike command that automatically cleans up unwanted dependencies and updates dependencies to the current version.

Major Version Upgrades

For example, v1.0.0 and v2.0.0 have different dependency paths. To do this, you can add a new path to go modules by modifying the first line of the go.mod file:

$ cd testmod
$ echo 'module github.com/objcoding/testmod/v2' >> go.mod
Copy the code

Then we modify the testmod function Hi() :

$ cd testmod

$ echo 'Package testmod import (" FMT ") func SayHello(name, STR string) string {return FMT.Sprintf(" %s, %s", name, str) }' >> testmod.go
Copy the code

In this case, the SayHello() method will not be compatible with v1, so we need to create a new v2.0.0 branch. As usual, we’d better create a new v2 branch from v2.0.0 and write the v2.0.0 code into this branch (this is just a specification, You can actually write code to any branch, Go doesn’t have this specification) :

$ git add *
$ git checkout -b v2
$ git commit testmod.go -m "v2.0.0"$git tag v2.0.0 $git push --tags origin v2Copy the code

At this time, the testmod version has been updated to v2.0.0, which is not compatible with the previous version, but currently the project can only obtain the dependent version of V1.0.1, because v2 has been added to the module path of testmod, so there will be no conflict problem. What if we need to use v2.0.0? We just need to change the import path in the project:

package main

import (
    "fmt"
  	"github.com/objcoding/testmod/v2"
)
func main(a) {
    fmt.Println(testmod.SayHello("Cheung Shing Fai"."How are you doing?"))}Copy the code

Perform:

go mod tidy
Copy the code

At this time, we have updated the testmod dependent version number to v2.0.0. Although the import path at this time ends with “v2”, Go is very user-friendly and we can still use testmod to use it.