标签 dep 下的文章

Go语言包管理简史

img{512x368}

包管理是Go一直被诟病做得不好的功能之一。先前版本(go 1.11之前)的主要缺点之一是go get是缺乏对依赖包版本的管理和对可复制构建(reproducible build)的支持。Go社区已经开发了一些包管理器和工具作为版本化包依赖的事实标准解决方案,如glidedep以及一些辅助工具等。

“我在生产构建中使用go get。” – 没有人这么说过。

Go语言的包管理实现可追溯到Google公司内的代码依赖管理(Google将内部所有源代码都存放在一个巨大的单体存储库中)。我们来分析一下在”Go module”之前Go语言的包管理工具都出了什么问题。

  • 依赖包的版本化
  • 依赖包的本地缓存(vendor)
  • GOPATH的必要性

依赖包的版本化

go get默认情况下不支持包版本控制。go软件包管理的第一版实现背后的想法是-不需要包版本控制,不需要第三方包存储库,您可以从当前分支中构建所有内容。

Go 1.11之前的版本中,添加依赖项意味着将该依赖项的源代码仓库克隆到$GOPATH下面。就是这样,没有版本的概念。版本始终指向克隆时刻的主分支。出现了另一个主要问题是,当不同的项目需要依赖包的不同版本时,Go包管理工具无法实现。

依赖包的本地缓存(vendor)

依赖包本地缓存通常是指相关依赖包与项目存储在同一位置。这通常意味着将您的依赖项源码也提交到源管理系统中,例如Git。

考虑这样一种情况- A使用依赖项B,而B使用了C版本在1.5版本中引入一个功能,这时B必须确保A在构建时使用的也是C 1.5或更高版本。在Go 1.5之前的版本中,没有一种机制可以在不重写导入路径的情况下将依赖包代码与命令绑定在一起。

GOPATH的必要性

GOPATH存在的主要原因有两个:

  1. 在Go中,import声明通过其完全限定的导入路径来引用包。GOPATH存在可以方便Go工具计算GOPATH/src内的任何目录所涉及软件包的绝对导入路径。
  2. 它是Go get命令存储包依赖项的位置。

这有什么问题?

  1. GOPATH 不允许开发人员像其他语言一样选择任意喜欢的目录签出项目的源代码。
  2. 此外,GOPATH不允许开发人员同时检出某个项目(或其依赖项)的多个副本。

Go Module介绍

Go 1.11引入了对Go模块(module)的初步支持。下面摘自Go Wiki:

一个模块是一组相关的Go包的集合,这个包集合被当做一个独立的单元进行统一版本管理。模块精确记录了依赖要求并支持创建可复制的构建。

Go模块带来了三个重要的内置功能:

  1. go.mod文件,它与package.json或Pipfile文件的功能类似。
  2. 机器生成的传递依赖项描述文件 – go.sum。
  3. 不再有GOPATH限制。模块可以位于任何路径中。
$ go help mod
Go mod provides access to operations on modules.

Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.

Usage:

    go mod <command> [arguments]

The commands are:

    download    download modules to local cache
    edit        edit go.mod from tools or scripts
    graph       print module requirement graph
    init        initialize new module in current directory
    tidy        add missing and remove unused modules
    vendor      make vendored copy of dependencies
    verify      verify dependencies have expected content
    why         explain why packages or modules are needed

Use "go help mod <command>" for more information about a command.

更多相关讨论在这里

迁移到Go Module

要使用Go模块,请更新Go到1.11及以上版本。由于不再需要GOPATH,因此可以通过以下两种方式之一激活模块支持(译注:下面的行为仅适用于Go 1.11~Go 1.12Go 1.13版本默认开启Go module,无论是否在GOPATH下,除非GO111MODULE=off):

  • 在GOPATH/src之外的目录中调用Go命令,并在当前目录中存在一个有效的go.mod文件。
  • 如果源码在GOPATH之下,Go模块将不起作用。要改变此行为,请设置环境变量GO111MODULE=on后再调用Go命令。

让我们通过以下简单的步骤开始迁移:

  • 由于GOPATH不再必要的了,将module移出GOPATH。

  • 在项目根目录中,创建初始模块定义 – go mod init github.com/username/repository。go mod还会自动转换现有的包管理器(如dep和Gopkg,glide以及其他六种)的依赖关系。这将创建一个名为go.mod的文件,该文件存储了模块名以及模块的依赖项及其版本。

$ cat go.mod
module github.com/deepsourcelabs/cli

go 1.12

require (
    github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e
    github.com/getsentry/raven-go v0.2.0
    github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9
)
  • 运行go build会创建一个go.sum文件,其中包含特定模块版本的内容的预期校验和。这是为了确保这些模块将来的下载内容与第一次下载是相同的。请注意,go.sum不是锁文件。
$ cat go.sum
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e h1:9574pc8MX6rF/QyO14SPHhM5KKIOo9fkb/1ifuYMTKU=
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9 h1:dIsTcVF0w9viTLHXUEkDI7cXITMe+M/MRRM2MwisVow=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

关于版本控制的注意事项:为了保持向后兼容性,如果模块的版本为v2或更高版本,则模板的主版本必须以/vN的形式被包含在go.mod文件中使用的模块路径的末尾。比如:module github.com/username/repository/v2

日常命令

列出依赖项

go list -m all 列出当前模块及其所有依赖项。

$ go list -m all
github.com/deepsourcelabs/cli
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e
github.com/getsentry/raven-go v0.2.0
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9

在go list输出中,当前模块(也称为主模块)始终是第一行,其后是路径排序所有依赖模块。

列出软件包的可用版本

go list -m -versions github.com/username/repository 列出软件包的可用版本。

$ go list -m -versions github.com/getsentry/raven-go
github.com/getsentry/raven-go v0.1.0 v0.1.1 v0.1.2 v0.2.0

添加依赖

添加依赖项是隐式的。在代码中导入依赖项后,运行go build或go test命令将获取模块的最新版本并将其添加到go.mod文件中。如果要显式添加依赖项,请运行go get github.com/username/repository。

依赖项的升级/降级

go get github.com/username/repository@vx.x.x下载并设置依赖项和更新go.mod文件的特定版本。

$ go get github.com/getsentry/raven-go@v0.1.2
go: finding github.com/getsentry/raven-go v0.1.2
go: downloading github.com/getsentry/raven-go v0.1.2
go: extracting github.com/getsentry/raven-go v0.1.2

$ cat go.mod
module github.com/deepsourcelabs/marvin-go

go 1.12

require (
    github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e
    github.com/getsentry/raven-go v0.1.2
    github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9
)

$ cat go.sum
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e h1:9574pc8MX6rF/QyO14SPHhM5KKIOo9fkb/1ifuYMTKU=
github.com/certifi/gocertifi v0.0.0-20190410005359-59a85de7f35e/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/getsentry/raven-go v0.1.2 h1:4V0z512S5mZXiBvmW2RbuZBSIY1sEdMNsPjpx2zwtSE=
github.com/getsentry/raven-go v0.1.2/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9 h1:dIsTcVF0w9viTLHXUEkDI7cXITMe+M/MRRM2MwisVow=
github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

vendor依赖项

使用模块时,go命令将完全忽略vendor目录。为了向后兼容旧版Go,或确保将用于构建的所有文件一起存储在单个文件树中,请运行go mod vendor。

这将在主模块的根目录中创建一个vendor目录,并将依赖模块中的所有软件包存储在该目录中。

注意:要使用主模块的顶级vendor目录进行构建,请运行’go build -mod=vendor’。

删除未使用的依赖项

go mod tidy将删除未使用的依赖项并更新go.mod文件。

常见问题解答

  1. GOPATH不再需要了?
    是,永别了GOPATH。

  2. 默认情况下拉取哪个版本?
    go.mod文件和go命令通常将语义版本用作描述模块版本的标准形式,以便可以比较版本以确定哪个版本应早于或晚于其他版本。v1.2.3通过在基础源存储库中标记(tag)修订来引入类似的模块版本。未标记(untag)的修订版可以使用“伪版本”之类的来引用:v0.0.0-yyyymmddhhmmss-abcdefabcdef,其中时间是UTC的提交时间,最后的后缀是提交哈希的前缀。

  3. go.sum应该被检入到版本库中吗?
    是。

鉴于本人近期较忙,又不希望让博客长草,近一段时间会挑选翻译一些笔者认为比较优秀的外文文章分享给大家。

本文翻译自《Package management in Go – brief overview of package management in Go — pre and post Go modules》


我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网上线了,感谢小伙伴们学习支持!

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

我的联系方式:

微博:https://weibo.com/bigwhite20xx
微信公众号:iamtonybai
博客:tonybai.com
github: https://github.com/bigwhite

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

Go module机制下升级major版本号的实践

Go module机制Go 1.11版本引入,虽然也伴随着不小的质疑声,但总体上Go社区多数Gopher是接受go module的,很多标杆式的Go项目(比如kubernetes、kubernetes client-go等)也都逐渐转向了Go module,并且Gopher也在向core team反馈了自己的建议和问题。Go core team也在go module最初设计的基础上持续进行着改进,比如:即将到来的Go 1.13版本中将增加默认GOPROXY(https://proxy.golang.org)、GOSUMDB(sum.golang.org);增加GONOPROXY、GONOSUMDB以应对私有module的处理;不断丰富的go mod子命令功能等。

随着Go module应用的日益逐步广泛和深入,Gopher们也开始遇到一些最初使用Go module时未曾遇到过的问题,比如升级major版本号(这是由于多数Go project仍处于untag的状态或者1.x.x状态,因此在go module引入初期,少有gopher遇到该类问题)。这篇文章我们就来简单看看如何在go module机制下面升级库的主版本号(major version number)。

一. Go module的“semantic import versioning”

在Russ Cox关于go module的系列论述文章“semantic import versioning”一文中,Russ说明了Go import包兼容性的总原则:

如果新旧版本的包使用相同的导入路径(import path),那么新包与旧包是兼容的。

也就是说如果新旧两个包不兼容,那么应该采用不同的导入路径。

因此,Russ采用了将“major版本”作为导入路径的一部分的设计。这种设计支持在同一个项目或go source文件中import同一个module下的package的不同版本。同一个package虽然包名字相同,但是import path不同。vN作为import path的一部分将用于区分包的不同版本。同时在同一个源文件中,我们可以使用包别名的方式来区分同一个包的不同版本,比如:

import (

    "github.com/bigwhite/foo/bar"

    barV2 "github.com/bigwhite/foo/v2/bar"

    ... ...

)

go module的这种设计对Go包的consumer(包的使用者)来说似乎并未有太多额外工作,但是这给Go包的author们带来了一定的复杂性,他们需要考虑在go module机制下如何将自己的Go module升级major version。稍有不慎,可能就会导致自身代码库的混乱或者package consumer侧无法通过编译或执行行为的混乱。

下面我们就从go package author的角度实践一下究竟该如何做module major版本号的升级。Go module为go package author提供了两种major version升级的方案,我们下面逐一看一下。我们的实验环境基于go 1.12.5 (ubuntu 16.04)。

二. 使用“major branch”方案

“major branch”方案对于多数gopher来说是一个过渡比较自然的方案,它通过建立vN分支并基于vN分支打vN.x.x的tag的方式做major version的升级。当然是否建立vN分支以及打vN.x.x tag都是一个可选的操作。

我们在bitbucket.org上建立一个公共仓库:bitbucket.org/bigwhite/modules-major-branch,其初始结构和代码如下(注意:此时本地开发环境中GO111MODULE=on):

# tree -LF 2 modules-major-branch
modules-major-branch
├── foo/
│   └── foo.go
├── go.mod
└── README.md

1 directory, 3 files

//go.mod

# cat go.mod
module bitbucket.org/bigwhite/modules-major-branch

go 1.12

// foo.go

package foo

import "fmt"

func Foo() {
        fmt.Println("foo.Foo of module: bitbucket.org/bigwhite/modules-major-branch pre-v1")
}

接下来,我们建立modules-major-branch/foo包的消费者项目:modules-major-branch-test

# tree -LF 1 ./modules-major-branch-test/
./modules-major-branch-test/
├── go.mod
├── go.sum
└── main.go

0 directories, 3 files

# cat go.mod
module bitbucket.org/bigwhite/modules-major-branch-test

go 1.12

# cat main.go
package main

import (
    "bitbucket.org/bigwhite/modules-major-branch/foo"
)

func main() {
    foo.Foo()
}

我们run一下“消费者”:

# go run main.go
go: finding bitbucket.org/bigwhite/modules-major-branch/foo latest
go: finding bitbucket.org/bigwhite/modules-major-branch latest
go: downloading bitbucket.org/bigwhite/modules-major-branch v0.0.0-20190602132049-2d924da2e295
go: extracting bitbucket.org/bigwhite/modules-major-branch v0.0.0-20190602132049-2d924da2e295
foo.Foo of module: bitbucket.org/bigwhite/modules-major-branch pre-v1

我们看到在这个阶段消费成功。

作为modules-major-branch的author,随着module功能演进,modules-major-branch到达了发布1.0版本的节点:

# cat foo/foo.go
package foo

import "fmt"

func Foo() {
    fmt.Println("foo.Foo of module: bitbucket.org/bigwhite/modules-major-branch v1.0.0")
}

# git tag v1.0.0
# git push --tag origin master

接下来,我们让consumer升级对modules-major-branch/foo的依赖到v1.0.0。这种升级是不会自动进行,是需要consumer的开发者自己决策后手工进行的,否则会给开发者带来困惑。我们通过go mod edit命令修改consumer的require:

# go mod edit -require=bitbucket.org/bigwhite/modules-major-branch@v1.0.0

# cat go.mod
module bitbucket.org/bigwhite/modules-major-branch-test

go 1.12

require bitbucket.org/bigwhite/modules-major-branch v1.0.0

我们来运行一下升级依赖后的程序:

# go run main.go
go: finding bitbucket.org/bigwhite/modules-major-branch v1.0.0
go: downloading bitbucket.org/bigwhite/modules-major-branch v1.0.0
go: extracting bitbucket.org/bigwhite/modules-major-branch v1.0.0
foo.Foo of module: bitbucket.org/bigwhite/modules-major-branch v1.0.0

从pre-v1到v1在最新的go module机制中还算不上major版本的升级,接下来我们就来看看foo包的作者应该如何对modules-major-branch module做出不兼容的升级:v1 -> v2。

当modules-major-branch module即将做出不兼容升级时,一般会为当前版本建立维护分支(比如:v1分支,并在v1分支上继续对v1版本进行维护、打补丁),然后再在master分支上做出不兼容的修改。

# git checkout -b v1

# git checkout master

# cat foo/foo.go
package foo

import "fmt"

func Foo2() {
    fmt.Println("foo.Foo2 of module: bitbucket.org/bigwhite/modules-major-branch v2.0.0")
}

从代码可以看到,在master分支上,我们删除了foo包中的Foo函数,新增了Foo2函数。但仅做这些还不够。在本文一开始我们就提到过原则:如果新旧两个包不兼容,那么应该采用不同的导入路径。我们为modules-major-branch module做出了不兼容的修改,也需要modules-major-branch module有着不同的导入路径,我们需要修改modules-major-branch module的module根路径:

# cat go.mod
module bitbucket.org/bigwhite/modules-major-branch/v2

go 1.12

# git tag v2.0.0
# git push --tag origin master

我们在module根路径后面加上了v2,并基于master建立了tag: v2.0.0。

我们再来看看consumer端应该如何应对modules-major-branch module的不兼容修改。如果consumer要使用最新的Foo2函数的话,我们需要对main.go做出如下改动:

//modules-major-branch-test/main.go

package main

import (
    "bitbucket.org/bigwhite/modules-major-branch/v2/foo"
)

func main() {
    foo.Foo2()
}

接下来我们不需要手工修改modules-major-branch-test的go.mod中依赖,直接运行go run即可:

# go run main.go
go: finding bitbucket.org/bigwhite/modules-major-branch/v2/foo latest
go: finding bitbucket.org/bigwhite/modules-major-branch/v2 v2.0.0
go: downloading bitbucket.org/bigwhite/modules-major-branch/v2 v2.0.0
go: extracting bitbucket.org/bigwhite/modules-major-branch/v2 v2.0.0
foo.Foo2 of module: bitbucket.org/bigwhite/modules-major-branch v2.0.0

我们看到go编译器会自动发现依赖变更,并下载对应的包并更新go.mod和go.num:

# cat go.mod
module bitbucket.org/bigwhite/modules-major-branch-test

go 1.12

require (
    bitbucket.org/bigwhite/modules-major-branch v1.0.0
    bitbucket.org/bigwhite/modules-major-branch/v2 v2.0.0 // indirect
)

modules-major-branch-test此时已经不再需要依赖v1.0.0了,我们可以通过go mod tidy清理一下go.mod中的依赖:

# go mod tidy
# cat go.mod
module bitbucket.org/bigwhite/modules-major-branch-test

go 1.12

require bitbucket.org/bigwhite/modules-major-branch/v2 v2.0.0

我们看到:现在就只剩下对modules-major-branch v2的依赖了。

后续modules-major-branch可以在master分支上持续演进,直到又有不兼容改动时,可以基于master建立v2维护分支,master分支将升级为v3(module)。

再小结一下:

对包的作者而言,升级major版本号需要:

  • 升级module的根路径,增加vN

  • 建立vN.x.x形式的tag(可选,如果不打tag,go会在consumer的go.mod中使用伪版本号,比如:bitbucket.org/bigwhite/modules-major-branch/v2 v2.0.0-20190603050009-28a5b8da279e)

如果modules-major-branch内部有相互的包引用,那么在升级major号的时候,这些包的import路径也要增加vN,否则就会存在在高major version的代码中引用低major version包代码的情况,这也是包作者最容易忽略的事情。github.com/marwan-at-work/mod是一个为module作者提供的升级/降级major version号的工具,它可以帮助包作者方便地自动修改项目内所有源文件中的import path。有gopher已经提出希望go官方提供upgrade/downgrade的支持,但目前core team尚未明确是否增加。

对于consumer而言,升级依赖包的major版本号,只需要在import包时在import path中增加vN即可,当然代码中也要针对不兼容的部分进行修改,然后go工具会自动下载相关包。

三. 使用 “major subdirectory”方案

go module机制还提供了一种我个人觉得较为怪异的方案或者说用起来不那么自然的方案,那就是利用子目录分割不同主版本。如果某个module目前已经演化到v3版本了,那么这个module所在仓库的目录结构应该是这样的:

# tree modules-major-subdir
modules-major-subdir
├── bar
│   └── bar.go
├── go.mod
├── v2
│   ├── bar
│   │   └── bar.go
│   └── go.mod
└── v3
    ├── bar
    │   └── bar.go
    └── go.mod

这里直接用vN作为子目录名字,在代码仓库中将不同版本module放置在不同的subdir中,这样即便不打tag,通过subdir也能找到对应版本的module包。以上图中的v2为例,该子目录下go.mod如下:

# cat go.mod
module bitbucket.org/bigwhite/modules-major-subdir/v2

go 1.12

v3也是类似。在各自子目录中,module的根路径都是带有vN扩展的。

接下来,我们就来创建consumer来分别调用不同版本的modules-major-subdir/bar包。和modules-major-branch-test类似,我们建立modules-major-subdir-test来作为consumer调用modules-major-subdir/bar包:

// modules-major-subdir-test

# cat go.mod
module bitbucket.org/bigwhite/modules-major-subdir-test

go 1.12

# cat main.go
package main

import (
    "bitbucket.org/bigwhite/modules-major-subdir/bar"
)

func main() {
    bar.Bar()
}

运行一下consumer:

# go run main.go

go: finding bitbucket.org/bigwhite/modules-major-subdir/bar latest
go: finding bitbucket.org/bigwhite/modules-major-subdir latest
go: downloading bitbucket.org/bigwhite/modules-major-subdir v0.0.0-20190603053114-50b15f581aba
go: extracting bitbucket.org/bigwhite/modules-major-subdir v0.0.0-20190603053114-50b15f581aba
bar.Bar of module: bitbucket.org/bigwhite/modules-major-subdir

我们修改main.go,调用v2版本bar包中Bar2函数:

package main

import (
    "bitbucket.org/bigwhite/modules-major-subdir/v2/bar"
)

func main() {
    bar.Bar2()
}

再次运行main.go:

# go run main.go
go: finding bitbucket.org/bigwhite/modules-major-subdir v0.0.0-20190603053114-50b15f581aba
go: downloading bitbucket.org/bigwhite/modules-major-subdir v0.0.0-20190603053114-50b15f581aba
go: extracting bitbucket.org/bigwhite/modules-major-subdir v0.0.0-20190603053114-50b15f581aba
go: finding bitbucket.org/bigwhite/modules-major-subdir/v2/bar latest
go: finding bitbucket.org/bigwhite/modules-major-subdir/v2 latest
go: downloading bitbucket.org/bigwhite/modules-major-subdir/v2 v2.0.0-20190603063223-4be5d54167e9
go: extracting bitbucket.org/bigwhite/modules-major-subdir/v2 v2.0.0-20190603063223-4be5d54167e9
bar.Bar2 of module: bitbucket.org/bigwhite/modules-major-subdir v2

我们看到:go编译器自动找到了位于modules-major-subdir仓库下v2子目录下的v2版本bar包。

从demo来看,似乎这种通过subdir方式来实现major version升级的方式更为“简单”一些。但笔者总感觉这种方式有些“怪”,尤其是在与tag交叉使用时可能会带来一些困惑,其他主流语言也鲜有使用这种方式进行major version升级的。另外一旦使用这种方式,似乎也很难利用git工具在不同major版本之间进行代码的merge(复用)了。

另外和major branch方案一样,如果module内部有相互的包引用,那么在升级major号的时候,这些包的import路径也要增加vN,否则也会存在在高major version的代码中引用低major version包代码的情况。

四. 小结

Go module作为主流语言依赖管理思路之外的一个“探索性”创新,势必在初期要有一段坎坷的道路要走。好事多磨,相信经过Go 1.11~Go 1.13三个版本的改进以及社区在工具方面对go module的逐渐的完善的支持,Go module会成为gopher日常Go开发的一柄利器,彻底解决Go的包依赖问题。

上述demo源码可在bitbucket.org/bigwhite下找到。

另外这里要提一点:国内的码云(gitee.com)目前对go module major version升级支持的还有问题。同样的操作,但在gitee.com下总是提示:“go.mod has post-v0 module path”


我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网上线了,感谢小伙伴们学习支持!

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

我的联系方式:

微博:https://weibo.com/bigwhite20xx
微信公众号:iamtonybai
博客:tonybai.com
github: https://github.com/bigwhite

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats