引言:
一般通过 go get
拉取的是公共仓库的代码(如: github.com中的代码),是不需要任务权限就能拉下来。但当我们配置的私有仓库一般都需要用户名密码来登录才能拉取代码,所以私有仓库主要是解决认证问题。
了解 go get
在早期版本的Go中,“go get”用于构建和安装包。现在,“go get”专门用于调整go.mod中的依赖项,即下载所需要的包。'go install'可以用来构建和安装命令。go get
通常也是使用 git、svn等工具进行拉取所需要的包。怎么决定使用哪个工具呢?
1. 通过静态方式
1.1 通过仓库域名
例如:go get github.com/example/pkg
域名为github.com
go就直接使用 git 工具进行拉取。
1.2 通过后缀
例如:go get github.com/example/pkg.git
后缀为.git
,也直接使用 git 工具进行拉取。
2. 通过动态方式
选择动态方式是因为域名和后缀都无法判断仓库类型,所以一般私有的仓库会使用动态方式。
通过在go get 命令中加 -v参数能够看到将请求的结果
go get -v git.test.com/example/pkg
2.1 询问仓库
go get 时,go 会先使用 //git.test.com/example/pkg?go-get=1
请求再从结果中判断使用哪个工具拉取。
2.2 分析结果
返回结果如下:
<html>
<head>
<meta name="go-import" content="git.test.com/example/pkg git http://git.test.com/example/pkg.git" />
<meta name="go-source" content="git.test.com/example/pkg http://git.test.com/example/pkg http://git.test.com/example/pkg/-/tree/master{/dir} http://git.test.com/example/pkg/-/blob/master{/dir}/{file}#L{line}" />
</head>
<body>go get http://git.test.com/example/pkg</body>
</html>
其中:<meta name="go-import" content="git.test.com/example/pkg git http://git.test.com/example/pkg.git" />
的content
的值分3段,格式为:
<meta name="go-import" content="root-path vcs repo-url" />
-
root-path: 模块名字,如:
git.test.com/example/pkg
-
vcs: 使用的管理工具,如: git
-
repo-url:指的是模块原代码存放在哪个仓库下面,该仓库就需要是协议加仓库地址的形式。如:
http://git.test.com/example/pkg.git
那么go就知道使用哪个工具拉取包了。
git认证
知道从哪里拉取、怎么拉取,正常就可以拉取go包了,但私有仓库需要git认证。git拉取代码认证的方式有3种:
URI的完整格式:
schema://username:password@host:port?query#fragment
•
schema: 协议,如http/https/ftp等
•
username: 用户名
•
password: 密码
•
host: ip或域名
•
port: 端口
•
query: 查询字符串
•
fragment: 锚点
1. 用户名、密码
需要在拉取时输入用户名密码,但go get时禁止交互(弹框,提示输入用户名密码),我们可以参考URI格式使用 URL中添加用户名密码,即可。但我们go get时也没办法去改这个呀,后面介绍使用 git的 insteadof解决。
如:http://root:passpwd@git.test.com/example/pkg
2. 用户名、access token(推荐使用)
作用和功能同1中的用户名、密码。只是一般用户名密码是用来登录的,如果把密码暴露了(因为这种认证会保存在git配置中,后面会介绍)就不太好了,本来只想让程序去拉取一个仓库代码,结果别人知道密码了,直接登录上去了。token生成时是可以设置权限的,更为安全,使用在拉取代码时只给 read_repository
权限即可。
3. ssh
可以在本地创建非对称的加密对(ssh-keygen)。把公钥放到仓库里面去。
git的insteadof
git的insteadof在拉取代码,发送请求前替换请求地址。格式如下:
git config --global url."https://$GIT_USER:$GIT_TOKEN@$GOPRIVATE".insteadOf "https://$GOPRIVATE"
表示在请求 https://$GOPRIVATE
仓库时,会被替换成 https://$GIT_USER:$GIT_TOKEN@$GOPRIVATE
,即包含了用户名和密码,所以会拉取成功。
注:必须设置成 --global 与 --system,git 支持 --global、--local、--system。
-
--system 作用范围太大了,此机器的其他用户或项目都使用了此设置。
-
--local只能针对当前项目(所以必须在项目所在目录,它会找.git目录中的设置),go使用git命令时目录可能存在问题。【未验证】
例如:
git config --global url."https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com".insteadOf "http://git.test.com"
表示在请求http://git.test.com
私有仓库的包时会被替换成https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com
,这里的root
是仓库的用户名,VUQsGPQdxy5CDQ9xEs24
是access token,
注:网上有人说 insteadOf后面的域名必须带 /
即http://git.test.com/
,insteadOf前端字符串必须带:
,即:https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com:
。可能是平台或配置原因。根据自己的实际情况替换即可。
例如:
go get -v git.test.com/example/pkg 前,先通过 //git.test.com/example/pkg?go-get=1 进行访问,看返回的页面的实际协议,如我这里body中的:go get http://git.test.com/example/pkg
那么说明我的go get git.test.com/example/pkg
将被替换为`go get http://git.test.com/example/pkg
(注:go 自动完成)
这时我需要将用户名和access token,添加上,所以要把 http://git.test.com
替换为https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com
(需要我们手动配置git config)
最终替换完的结果将是:https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com/example/pkg
这时go会使用最终的地址进行git clone https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com/example/pkg
完整流程
-
1.
在GOPRIVATE环境变量中加入私有仓库地址。
go env -w GOPRIVATE=git.test.com
此时另外两个GO的环境变量正常也会自动被设置与GOPRIVATE设置的值相同:(如果没有改过来,请自行检查并修改)
set GONOPROXY=git.test.com # 拉取git.test.com时不使用GOPROXY代理服务器 set GONOSUMDB=git.test.com # 拉取包成功后不进行签名校验,因为我们的私有库没有生成签名
-
2.
设置git config地址替换
git config --global url."https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com".insteadOf "http://git.test.com"
这个设置会被保存在git全局的配置文件中。如我的window位置为:
C:\Users\lxz\.gitconfig
文件内容如下:
...省略不相关的配置 [url "https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com"] insteadOf = http://git.test.com
小知识点:引号中的内容会被设置在配置项目名称后面,中括号内(如:
https://root:...
),不带引号被设置在配置项内部(如:insteadOf
) -
3.
进行拉取即可
go get git.test.com/example/pkg
其他
1. 有时候配置了 git config 的insteadOf 后还是不好使,可能是因为之前设置过,需要把之前的删除。
先查看所有设置
> git config --global -l
# 结果显示
...省略不相关的配置
url.https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com.insteadof=http://git.test.com
...省略不相关的配置
再进行删除(复制=号之前的所有字符串)
git config --global --unset url.https://root:VUQsGPQdxy5CDQ9xEs24@git.test.com.insteadof
2. 凭证管理
git凭证管理和git本身是两个独立的程序,凭证管理工具位置有git安装目录中,例如我的目录C:\Program Files\Git\mingw64\libexec\git-core
下会有:
git-credential-cache.exe
git-credential-cache--daemon.exe
git-credential-manager-core.exe
git-credential-store.exe
git-credential-wincred.exe
查看git使用的凭证管理工具:
> git config --list
...省略不相关的配置
credential.helper=manager-core
credential.helper=store
...省略不相关的配置
Git 甚至允许你配置多个辅助工具。 当查找特定服务器的凭证时,Git 会按顺序查询,并且在找到第一个回答时停止查询。 当保存凭证时,Git 会将用户名和密码发送给 所有 配置列表中的辅助工具,它们会按自己的方式处理用户名和密码。
注意,这里的manager-core
和store
分别对应目录C:\Program Files\Git\mingw64\libexec\git-core
下的git-credential-manager-core.exe
和git-credential-store.exe
。当然你也可以自己写一个辅助工具,放在这个目录里。例如你开发一个:foo
的工具,你设置时使用git config --global credential.helper foo
,你的文件名称应该为:git-credential-foo.exe
git-credential-manager-core.exe
是微软开发的工具,它把凭证保存在了windows的凭证管理中。控制面板\用户帐户\凭证管理\管理windows凭证
中。所以有时有的人把 git config中的insteadof已经删除了,但还可以正常拉取。是因为系统已经把凭证保存起来了,我们拉取代码的时候git自动从凭证管理功能中获取到凭证,再拼接上进行请求。
3. go mod cache
go get 拉取代码时后在$GOPATH/pkg/下生成缓存,而且会有2级缓存。
第1级缓存:首先会在$GOPATH/pkg/mod/cache目录中下载所需要的包,以压缩所格式保存。
第2级缓存:在$GOPATH/pkg/mod中解压cache中的包,放在与cache目录同级。
这样我们 go get 时会先检查第2级缓存,如果不存在,再去检查第1级缓存,如果都不存在再连网去仓库拉取包,并生成缓存。
可以手动删除缓存或通过命令(命令会将整个$GOPATH/pkg/mod目录删除):
go clean -modcache
所以有时在认证后拉取的包缓存在了本地,即使认证的access token或密码修改了,再go get或go mod tidy时也可以成功使用包,也可能是使用了之前的缓存。
参考文章
Git 凭据保存、如何修改_git凭据怎么设置_薛瑄的博客-CSDN博客
Go Modules Reference - The Go Programming Language
更新精彩文章请关注微信公众号:大胡几哥哥