Reference: https://blog.golang.org/v2-go-modules
You have a dependency you want to use, like github.com/integralist/delete-just-testing
.
// delete-just-testing/foo/foo.go
//
package foo
import "fmt"
func Bar() {
fmt.Println("bar")
}
That dependency has the following go.mod
file:
module github.com/integralist/delete-just-testing
go 1.15
Note: Major version suffixes are not allowed at major versions v0 or v1 (e.g. you can't do
module github.com/integralist/delete-just-testing/v1
). There is no need to change the module path between v0 and v1 because v0 versions are unstable and have no compatibility guarantee. Additionally, for most modules, v1 is backwards compatible with the last v0 version; a v1 version acts as a commitment to compatibility, rather than an indication of incompatible changes compared with v0. -- official reference.
We want to create a new program, so we start by initializing a new go module for our project:
go mod init testing_gomodules
We create an app.go
main package:
package main
import (
"fmt"
"github.com/integralist/delete-just-testing/foo"
)
func main() {
fmt.Println("main")
foo.Bar()
}
We execute go run app.go
and find our go.mod
file is updated:
$ go run app.go
go: finding module for package github.com/integralist/delete-just-testing/foo
go: downloading github.com/integralist/delete-just-testing v0.0.0-20200921145455-530f3130809d
go: found github.com/integralist/delete-just-testing/foo in github.com/integralist/delete-just-testing v0.0.0-20200921145455-530f3130809d
main
bar
The go.mod
file for our project now looks like:
module testing_gomodules
go 1.15
require github.com/integralist/delete-just-testing v0.0.0-20200921145455-530f3130809d // indirect
Note: when I was running through this example I had pulled in the dependency into my project before I had actually assigned a
v1.0.0
tag, so the go toolchain generates a pseudo-version for you. If I had tagged the commit withv1.0.0
before trying to use the dependency then instead of the pseudo-version I would have seenv1.0.0
after the module path.
If we (as the dependency author) want to update our code to be v2, then we have two strategies:
- create a new
v2/
directory and copy our package into it (this is for backwards compatibility with go versions below 1.13 that don't understand go modules). - just rename the module in the
go.mod
file (which will require you to update all explicit imports in your code's test files + consumers will need to do the same).
Note:
go get -u
doesn't help consumers of our dependency get the latest major version. If you rungo list -u -m all
you'll see minor and patch updates but not major version updates. This goes back to how the go team perceive v2 and higher major version releases (i.e. they should be a different directory or new module path).
Now let's say we take the second approach of just changing the go.mod
name in our dependency repository:
module github.com/integralist/delete-just-testing/v2 // << updated to append /v2
go 1.15
Then the consumer will need to update their import path to get that change:
package main
import (
"fmt"
"github.com/integralist/delete-just-testing/v2/foo" // << updated to include /v2
)
func main() {
fmt.Println("main")
foo.Bar()
}
...they'll also discover they have an updated go.mod
:
module testing_gomodules
go 1.15
require (
github.com/integralist/delete-just-testing v0.0.0-20200921145455-530f3130809d
github.com/integralist/delete-just-testing/v2 v2.0.0
)
You'll see we have the tagged v2.0.0
pulled in alongside the original. Running go mod tidy
will remove the old version.
Note: if you change the import path back to the non
/v2
version you'll discover the oldv0.0.0...
pseudo-version is put back into yourgo.mod
file and you can again usego mod tidy
to remove thev2.0.0
dependency. This is cool, because although the old pre-v2 code doesn't exist any more at HEAD in the dependency'smaster
branch, the go toolchain is still able to retrieve it.
Imagine you're using a package called go-fastly
and it's currently defined at version 2.0.0
so it uses /v2
in its module path. But then an upgrade to 3.0.0
is released so you need to bump your imports from v2
to reference v3
.
:Ack! --go 'go-fastly/v2'
:cdo s/v2/v3/ | update
If you don't have Ack! because you're using a basic vim configuration (e.g. vim -u ~/.vimrc-basic
), then use the following instead...
:vimgrep /go\-fastly\/v2/j fastly/*go
:copen
:cdo s/v2/v3/ | update
NOTE: The reason to use
vim -u ~/.vimrc-basic
is because of vim-go and the golang LSP can cause the Vim quickfix window to get updated (various warnings/errors etc about the code) and this means:cdo
fails to complete as the quickfix list it was working with has changed. So using a basic Vim configuration means I can use:cdo
and have the files updated in a fraction of the time as no LSP means much faster processing.