Go Modules:找出所需包的正确伪版本(vX.Y.Z-<timestamp>-<commit>)

Go Modules: finding out right pseudo-version (vX.Y.Z-<timestamp>-<commit>) of required package

我正在试用 Go 模块。我的项目需要库 golang.org/x/net/html,所以我定义了这个 go.mod 文件:

module github.com/patrickbucher/prettyprint

require golang.org/x/net/html

并编写了这个演示程序来检查编译时是否加载了依赖项:

package main

import (
        "fmt"
        "log"
        "os"

        "golang.org/x/net/html"
)

func main() {
        doc, err := html.Parse(os.Stdin)
        if err != nil {
                log.Fatal(err)
        }
        fmt.Println(doc)
}

当我 运行 进行构建时,我收到此错误消息:

go: errors parsing go.mod:
~/prettyprint/go.mod:3: usage: require module/path v1.2.3

显然,我错过了版本号。但是拿哪一个呢?我偶然发现了一篇名为 Takig Go Modules for a Spin 的文章,在那里我找到了一个 go.mod 文件的示例,其中包含对 golang.org/x 包的引用:

module github.com/davecheney/httpstat

require (
        github.com/fatih/color v1.5.0
        github.com/mattn/go-colorable v0.0.9
        github.com/mattn/go-isatty v0.0.3
        golang.org/x/net v0.0.0-20170922011244-0744d001aa84
        golang.org/x/sys v0.0.0-20170922123423-429f518978ab
        golang.org/x/text v0.0.0-20170915090833-1cbadb444a80
)

作者使用的版本字符串如 v0.0.0-20170922011244-0744d001aa84,由 semver 指示 v0.0.0、时间戳和看起来像 git 提交 ID 的内容组成。

如何找出这些版本字符串?我猜这些 golang.org/x 包在某些时候会根据语义版本控制进行版本控制,但要真正尝试 go mod,我需要弄清楚那些 now.

现在我进一步阅读了文档 (go help modules) 并偶然发现 go mod tidy:

The 'go mod tidy' command builds that view and then adds any missing module requirements and removes unnecessary ones.

因此,当我放弃对 golang.org/x/net/html 的要求并 p运行e 我的 go.mod 文件时:

module github.com/patrickbucher/prettyprint

然后是运行go mod tidy,然后根据我源码中的导入路径正确算出版本号的需求,然后因此 go.mod 变成:

module github.com/patrickbucher/prettyprint

require golang.org/x/net v0.0.0-20180906233101-161cd47e91fd

现在 go listgo build 都可以使用了。

v0.0.0-20180906233101-161cd47e91fd 形式的版本意味着 git 存储库中没有标记的版本。所以go mod根据最新的提交时间和提交哈希的前缀生成一个。

要获得正确的 go.mod 文件,请使用以下命令开始(假设 go 1.11):

go mod init yourmodulename

或者创建一个只包含以下内容的空 go.mod 文件:

module yourmodulename

然后运行 go mod tidy,这将找到所有依赖项,添加缺少的并删除未使用的依赖项。

The author is using version strings like v0.0.0-20170922011244-0744d001aa84, consisting of the semver indication v0.0.0, a timestamp and something that looks like a git commit ID.

How do I figure out those version strings?

您永远不需要手动找出那些称为 pseudo-versions.

的复杂版本字符串

日常工作流程

您典型的日常工作流程可以是:

  • 根据需要将导入语句添加到您的 .go 代码中。
  • go buildgo testgo mod tidy 等标准命令将根据需要自动添加新的依赖项以满足导入(更新 go.mod 并下载新的依赖项)。默认情况下,将使用新的直接依赖项的 @latest 版本。
  • 需要时,可以使用以下命令选择更具体的依赖项版本:
    • go get foo@v1.2.3
    • go get foo@e3702bed2
    • go get foo@latest
    • go get foo@branch
    • 或直接编辑 go.mod

请注意,在任何这些示例中,您都不需要自己提出伪版本,即使在请求特定提交(例如,@e3702bed2)或最近一次提交时也是如此分支(例如,@master)。

我什么时候会在 go.mod 中看到伪版本?

如果您最终在 go.mod 文件中得到一个解析为有效 semver tag with a leading v such as v1.2.3 or v1.2.4-beta-1, then that semver tag will be recorded in your go.mod file. If the version does not have a valid semver tag, then it will be instead recorded with as a pseudo-version 的版本,例如 v0.0.0-20171006230638-a6e239ea1c69,其中包括版本部分、提交时间戳和提交哈希。

在您的特定情况下,golang.org/x/net/html 没有任何 semver 标签,这意味着如果您执行 go get golang.org/x/net/html@latest,或 go get golang.org/x/net/html@0744d001aa84,或者先执行 go build在你的 .go 文件中包含 import "golang.org/x/net/html",然后 golang.org/x/net/html 将作为伪版本记录在你的 go.mod 中,但请注意,你不需要弄清楚自己复杂的字符串(因为go命令在需要的时候把modules queries比如go get golang.org/x/net/html@0744d001aa84翻译成对应的伪版本,把结果记录在你的go.mod里)。

为什么选择伪版本格式?

伪版本格式有助于提供基于标准 semver 排序的所有版本的简单总排序,这使得更容易推断出哪些提交将被视为 "later" 而不是另一个提交,或者是否将实际的 semver 标签视为 "later" 而不是单独的提交。

控制依赖版本

您可以在 Go Modules wiki 的 "How to Upgrade and Downgrade Dependencies" 部分阅读有关上述所有内容的更多信息,其中还包含指向官方文档的其他链接。

更新

此命令是将 replace 命令添加到 go.mod 的更好解决方案,而不是使用我最初发布的 git 手动执行:

go mod edit -replace github.com/docker/docker=github.com/docker/engine@ea84732a7725

产生类似的结果,但不是使用伪版本,而是找到标记的引擎版本。

replace github.com/docker/docker => github.com/docker/engine v17.12.0-ce-rc1.0.20191113042239-ea84732a7725+incompatible

或者,包括一个标记的 docker 版本。

go mod edit -replace github.com/docker/docker@v1.13.1=github.com/docker/engine@ea84732a7725

replace github.com/docker/docker v1.13.1 => github.com/docker/engine v17.12.0-ce-rc1.0.20191113042239-ea84732a7725+incompatible

感谢@Shivam010 on Medium


原始的、已弃用的答案

我是这样做的。

在所需 branch/tag 上检查存储库。例如

git clone -b v19.03.5 git@github.com:docker/engine.git

然后

cd engine
TZ=UTC git --no-pager show \
  --quiet \
  --abbrev=12 \
  --date='format-local:%Y%m%d%H%M%S' \
  --format="%cd-%h"

然后我得到

20191113042239-ea84732a7725

go.mod中用作

replace github.com/docker/docker v1.13.1 => github.com/docker/engine v0.0.0-20191113042239-ea84732a7725

如果您想使用尚未标记的特定提交,您可以执行以下操作 -

module github.com/patrickbucher/prettyprint

require golang.org/x/net 73496e0df0ba4284f460d1955ddf6bb096957c9f

然后运行 go mod tidy你会自动在go.mod文件中看到伪版本,变成

module github.com/patrickbucher/prettyprint

require golang.org/x/net v0.0.0-20180906233101-161cd47e91fd

(我借用了上面 Patrick 的回复中的代码片段)