说明: GHE指代GitHub Enterprise

这两天在工作环境中遇到一个奇怪的问题,使用go get github.com可以正确clone github 仓库代码,但是如果是公司内部私服(GHE),就会出现问题:


问题

在命令行中输入如下命令

go get -v -insecure github.com/your_private_repository

  • -v指打印详细信息

  • -insecure指先以https协议请求(默认), 如果请求结果不是200,再以http协议重新请求

你将会得到如下错误

Fetching https://github.com/your_private_repository?go-get=1
https fetch failed: Get https://github.com/your_private_repository?go-get=1: dial tcp 192.168.192.17:443: getsockopt: connection refused
Fetching http://github.com/your_private_repository?go-get=1
Parsing meta tags from http://github.com/your_private_repository?go-get=1 (status code 404)
package github.com/your_private_repository: unrecognized import path "github.com/your_private_repository" (parse http://github.com/your_private_repository?go-get=1: no go-import meta tags ())

但是如果这样输入,则可以下载下来

go get -v -insecure github.com/your_private_repository.git (注意这后面多了.git后缀)

但是很不幸这样下载下来的目录结构也带入了.git字样,于是工程里面所有指向自己工程包的引用都出现问题.

所以问题就是私有库url不带.git后缀就访问不了, 带了.git后缀,下载下来的路径就错了。


为什么GitHub public仓库就可以不用带.git访问呢?

原来go get 命令和 git clone命令不是等价的,通常我们执行一个go get 命令下载一个github.com的public 仓库,过程如下:

如果go get 的url中带了.git后缀的话,schema就会变成git协议,此时的url默认会变成下面这个样子

go get git://github.com/your_public_repository.git,

而git协议的url golang当然知道用git命令下载,所以带.git后缀的url可以被成功下载, 如果不带.git的话,go get 就默认使用https,结果就变成了下面这样

go get https://github.com/your_public_repository

这条命令其实又会分为如下几步:

  1. 首先请求该地址的头部信息,结果类似

curl -I https://github.com/your_public_repository

  1. 从header返回信息里查找 go-import metadata
  1. 根据meta信息决定使用什么工具,如git,svn等

所以url可以不带.git的关键是url返回的header里必须包含meta信息,或者是知名的域名也可以不带,比如github.com, 事实上github带上.git反而会报错,非知名域名才会按照meta tag策略来执行


GHE为什么不带.git就访问不了?

很简单,直接用浏览器打开一个GHE的地址,没有登录的情况下,返回了404页面。而404页面的header里并没有包含任何go-import meta-tag

我从下面这个golang的bug report里找到了问题的答案,链接地址

https://github.com/golang/go/issues/17898,

原来一直有个golang的bug没有解决这个问题,就在于golang和GitHub相互推脱,golang说自己已经提供了meta-tag的方式,让github在404页面也加入meta-tag,但github说自己为了保护私有库信息不被泄露,必须404不给任何信息,这样可以防止有人恶意猜测私有库信息(说的其实有道理)。两边就互不相让。后来一个哥们发现github上几乎所有页面都包含了一个header(”Server: GitHub.com”),亲测确实在404页面也包含。所以这哥们就给golang打了个补丁,把这个问题就解决了,可是golang这个斯却迟迟不把这个补丁加进来,从1.8等到了1.9,到现在也没加入进来,最后看这个bug的回复是:


Moving to Go 1.11. I hope we'll have a more comprehensive story around company repos then.

@rsc rsc modified the milestones: Go1.10, Go1.11 19 days ago

坑爹啊!!!


解决方案

  1. 自己加入上面这哥们说的补丁, 地址
    https://go-review.googlesource.com/c/go/+/33171
  2. 搭建一个agent server,对于GHE的404 page,在response里加入meta tag
  3. 使用Git clone 代替go get,自己手动创建目录结果,手动维护
  4. 在项目代码里包引用路径里加入.git(官方推荐),当然go get 命令里也要加上.git

文章来源于互联网,如有雷同请联系站长删除:关于go get GHE repository 404问题的研究

发表评论