【问题标题】:Package version management in Go 1.5Go 1.5 中的包版本管理
【发布时间】:2016-01-13 19:47:37
【问题描述】:

我开始接触 Go,虽然我理解并欣赏 Go 所基于的简单性原则,但我想了解放弃 背后的理由在他们的依赖获取工具go getimport语句中内置了包版本控制方法

如果我理解正确,go getimportHEAD 获取包,它们无法引用分支或标签。虽然有像gopkg.in 这样的工具可以绕过这个限制,但官方工具链:

  1. 强制开发人员为其产品的主要(破坏性)版本创建单独的存储库。
  2. 它不允许消费者在次要版本或微型版本之间降级,以防在较新版本中发现错误。

说实话,事情并不那么容易,因为包版本控制需要一种策略来处理冲突的传递依赖,例如X 依赖于AB,它们分别依赖于不同版本的C

来自 Java 背景,这种限制似乎带来了一些风险和问题,其中包括:

  1. 产品/包的演变和第 3 方部门的公共 API 的破坏是不可避免的,因此版本控制必须是工具链中的一等公民恕我直言。

  2. Git-repo-per-version 策略非常低效:

    • 包的整体 Git 历史记录丢失或分散在存储库中(版本之间的合并、反向移植等)
    • 可能仍会发生与传递依赖关系的冲突,并且会因为语言或工具链强加任何语义以首先允许检测而无法检测到。
  3. 企业采用可能会受到阻碍,开发团队可能会回避该语言,因为:

    • 总是拖入HEAD 意味着他们无法控制或冻结他们的第 3 方部门,从而导致最终产品可能无法预测。
    • 可能缺乏人力来不断更新产品并通过上游的HEAD 进行测试(并非世界上所有公司都是 Google :))。

虽然我明白后一种风险可以——而且必须——通过持续集成来缓解,但它并不能解决问题的根本原因。

我缺少什么信息?在人力有限的企业部署 Go 时如何处理包上游变更?

【问题讨论】:

  • 您可以使用供应商进口。通过将go get 设计为从 HEAD 中提取,它可以更轻松地提取错误修复并迫使 API 开发人员更加注意向后不兼容的更改。也就是说,这显然是一个基于意见的问题,这不是 StackOverflow 的主题。
  • 我明白了。我改变了措辞以避免基于意见的答案。如果您能详细说明供应商导入——或其他在企业中部署 Go 的策略,而无需处理不断的上游变化,我将不胜感激。

标签: go


【解决方案1】:

vendoring 正在解决这个问题,它是 Go 1.5 的一部分,作为实验性功能,如果 go 命令在其环境中使用GO15VENDOREXPERIMENT=1 运行,则可以启用它,并将成为 Go 中的“完整”功能1.6.另见Vendor Directories

可以在here 找到导致 Go 1.5 Vedor Experiment 的原始讨论。

vendoring 的本质是创建一个名为vendor 的文件夹,并放置代码所依赖的包的确切版本。 vendor 文件夹中的代码只能通过以vendor 的父级为根的目录树中的代码导入,并且您可以使用导入路径从vendor 导入包,就像vendor 将是workspace/src文件夹(即,导入路径省略了直到并包括供应商元素的前缀)。

例子:

/home/user/goworkspace/
    src/
        mymath/
            mymath.go
            vendor/
                github.com/somebob/math
                    math.go

在此示例中,github.com/somebob/mathmymath 包(来自mymath.go)使用的外部包。它可以从mymath.go 使用,如果它像这样导入:

import "github.com/somebob/math"

(而不是像import mymath/vendor/github.com/somebob/math那样会很糟糕。)

【讨论】:

    【解决方案2】:

    虽然 Go 没有附带标准包管理器,但有足够的选项可以使构建可重现(即使在人力有限的企业中)。

    1. 供应商,@icza 在另一个答案中对此进行了描述。这几乎完全等同于在 Java 中签入版本控制的 jar 文件。在 maven 流行之前,这是使用 ant 构建工具非常常见的方法。实际上,供应商要好得多,因为您不会丢失源代码。

    2. 这是第一个选项的轻微变化。您可以在构建期间通过检查依赖项的预定义版本来填充供应商文件夹,而不是签入供应商的源代码。有一些工具(例如 glide)可以自动执行这个过程。

    3. 最后,您可以在内部存储库中维护所有 3-rd 方库的预定义版本并将其添加到 GOPATH。这种方法在https://blog.gopheracademy.com/advent-2015/go-in-a-monorepo/

    4. 中有详细描述

    请注意,不兼容的传递依赖并不特定于 Go。它们也存在于 Java(和大多数其他语言)中,尽管 Java 有一种机制可以通过使程序更复杂来部分解决这个问题 - 类加载器。请注意,Go 将在编译时报告所有不兼容性,而在 Java 中,某些不兼容性仅在运行时触发(因为延迟链接)。

    Java 工具链没有版本的概念。它由外部工具 - maven 提供。我相信随着 Go 变得更加成熟和流行,类似的标准依赖管理工具将会出现。

    【讨论】:

    • 我的意思是,Java 甚至没有尝试在标准工具包中解决第三方包采购问题。 Java 留下了一个由 Maven + 其他基于 Maven 存储库的工具填补的空白,而 Maven 已经成为事实上的工具。相反,Go 确实在其工具集中解决了 3rd 方包采购问题,因此不早点考虑版本或供应商管理似乎是一种疏忽。最后,当我提到传递依赖时,我指的是 Maven 在构建时用于版本寻址和冲突报告的语义。
    • 抱歉,您的问题不是很清楚。我只能猜测 go 工具链缺乏版本支持,因为它的作者(和许多其他人;)从来都不是问题。据我所知,Maven 没有报告任何版本冲突。它尽最大努力解决传递依赖的版本,尽管通常您必须明确指定它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    • 2018-11-16
    • 2020-07-01
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多