Golang中为什么url.<base>.insteadOf不再支持go get命令?

Golang中为什么url.<base>.insteadOf不再支持go get命令? 我有一个Go项目存放在用于内部开发的BitBucket主机的Git仓库中。我们使用以ssh://git@source.example.com:7999/开头的Git远程URL,但BitBucket总是告诉Go URL应以https://source.example.com/scm/开头。因此我在~/.gitconfig中配置了以下内容:

[url "ssh://git@source.example.com:7999/"]
	insteadOf = https://source.example.com/scm/

这个配置过去一直有效,但不知从何时起失效了。请看:

$ go get -v -d -t -u ./...
Fetching https://source.example.com/iol/thingy?go-get=1
Parsing meta tags from https://source.example.com/iol/thingy?go-get=1 (status code 200)
get "source.example.com/iol/thingy": found meta tag get.metaImport{Prefix:"source.example.com/iol/thingy", VCS:"git", RepoRoot:"https://source.example.com/scm/iol/thingy.git"} at https://source.example.com/iol/thingy?go-get=1
package source.example.com/iol/thingy: source.example.com/iol/thingy is a custom import path for https://source.example.com/scm/iol/thingy.git, but /Users/david/dev/go/src/source.example.com/iol/thingy is checked out from ssh://git@source.example.com:7999/iol/thingy.git

我已经非常仔细地对比了这些字符串,它们看起来都是正确的。我遗漏了什么?


更多关于Golang中为什么url.<base>.insteadOf不再支持go get命令?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

感谢提供详细信息。您能否确认您的 Git 版本?

更多关于Golang中为什么url.<base>.insteadOf不再支持go get命令?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


$ git version
git version 2.17.1

目前尚不清楚您的代码库是私有还是公开,以及您使用的 Go 语言版本。

格式为 go get {host名}/{项目密钥}/{仓库别名}

根据 相关 issue 的描述,在某些情况下这仍然是一个问题。

func main() {
    fmt.Println("hello world")
}

啊,确实如此,这样修复了问题:

git remote set-url origin https://source.example.com/scm/iol/thingy.git

好的我明白了。真希望几个月前就能想到这一点!使用 -f 选项大致是等效的:拉取操作可以正常工作,只是忽略了远程地址与导入路径不同的事实。我猜这是必要的,因为 go get 不知道要读取 ~/.gitconfig

我之前使用的是Go 1.10版本,但刚升级到1.11.1后发现了同样的问题。

这个代码库确实是私有的,但通过将https网址替换为ssh网址,它应该能透明地使用我加载到SSH代理中的密钥。在我看来这像是Git未能正确替换网址,但我无法看到Git实际解析出的网址是什么。

不过或许我可以验证一下?这个方法似乎可行:

git ls-remote -q  https://source.example.com/scm/iol/thingy.git
33a5a7f71387172ea37cb45edee948e0ce33f3bf	HEAD
cd27380a4fc3f3aff64b9910bd3e14a5c0c3be07	refs/heads/develop
33a5a7f71387172ea37cb45edee948e0ce33f3bf	refs/heads/master
22dc734031e04ccf01a95e366451eb65522b84a5	refs/tags/v0.2.0
a3a0c4eb87b1d0f28839d4b93f51e11602459b8b	refs/tags/v0.2.0^{}

看起来Git能够正确解析网址。如果我在~/.gitconfig中修改网址,这个命令就会返回错误,因此我知道至少git客户端能正确更改网址。也许我还需要为这些克隆版本修改远程网址?

在Go 1.13及更高版本中,go get命令对Git URL重写规则的处理方式发生了变化。url.<base>.insteadOf配置在go get中的支持确实受到了限制,这是因为Go模块系统引入了更严格的版本控制和安全性要求。

问题在于Go模块现在会验证仓库的实际URL是否与模块路径声明的URL匹配。当使用insteadOf重写时,Go会检测到实际克隆的URL(ssh://git@source.example.com:7999/iol/thingy.git)与模块元数据声明的URL(https://source.example.com/scm/iol/thingy.git)不匹配,因此报错。

解决方案是使用Go模块的replace指令或环境变量配置:

方法1:使用go.mod中的replace指令

在项目的go.mod文件中添加:

module your-project

go 1.19

replace source.example.com/iol/thingy => ssh://git@source.example.com:7999/iol/thingy.git v0.0.0

方法2:使用GOPRIVATE环境变量

设置环境变量,告诉Go工具链这些是私有仓库,跳过严格的验证:

export GOPRIVATE=source.example.com

或者永久添加到shell配置文件中:

go env -w GOPRIVATE=source.example.com

方法3:使用Git配置的insteadOf结合GOPRIVATE

保持现有的Git配置,但必须设置GOPRIVATE:

go env -w GOPRIVATE=source.example.com

这样配置后,Go工具链会对source.example.com下的包跳过公共仓库的验证步骤,允许使用SSH URL进行克隆。

错误信息中显示的实际问题是URL不匹配,通过上述任一方法都可以解决这个问题。推荐使用方法2或3,因为它们提供了更灵活的配置方式。

回到顶部