说明: 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
这条命令其实又会分为如下几步:
- 首先请求该地址的头部信息,结果类似
curl -I https://github.com/your_public_repository
- 从header返回信息里查找 go-import metadata
<meta name="go-import" content="github.com/your_repository git https://github.com/our_repository.git">
- 根据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
坑爹啊!!!
解决方案
- 自己加入上面这哥们说的补丁, 地址
https://go-review.googlesource.com/c/go/+/33171 - 搭建一个agent server,对于GHE的404 page,在response里加入meta tag
- 使用Git clone 代替go get,自己手动创建目录结果,手动维护
- 在项目代码里包引用路径里加入.git(官方推荐),当然go get 命令里也要加上.git