英文:
Fetch 'go get' project from local bare git repo
问题
我正在尝试将远程存储库模拟为本地git存储库,我知道go mod edit -replace
等命令,但是对于我的用例,我需要使用Go命令从本地git存储库获取依赖项。
为了用最小的可重现示例模拟它,我创建了一个裸的git存储库:
# 在 /tmp/git/repo1 目录下
git init --bare
然后克隆该存储库,创建go项目,并将其推送回去:
# 在 /tmp/projects/ 目录下
git clone file:///tmp/git/repo1
cd repo1
go mod init git.localhost/repo1
git add go.mod && git commit -m "init: go mod init localhost" && git push origin
为了确保裸存储库已成功更新:
# 在 /tmp/git/repo1 目录下
git cat-file -p $(cat refs/heads/master) | grep init
# init: go mod init localhost
然后我创建了一个名为"client"的go项目,更新了git配置,并尝试使用go get
获取它:
# 在 /tmp/go-proj 目录下
go mod init example.com
git config --global url."file:///tmp/git/".insteadOf "https://git.localhost/"
go get git.localhost/repo1
但是出现了以下错误:
go: unrecognized import path "git.localhost/repo1": https fetch: Get "https://git.localhost/repo1?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
我还尝试更新GOPRIVATE
环境变量,并为file
协议设置git配置allow=always:
export GOPRIVATE="git.localhost/*"
git config --global protocol.file.allow always
并通过以下方式检查git是否可以克隆该存储库:
git clone https://git.localhost/repo1
# 成功从裸存储库克隆
是否可能使用go get
从本地git裸存储库获取依赖项?
更新:
添加了GOPROXY
环境变量,所以现在我的go env
输出为:
GOPRIVATE="git.localhost/*"
GOPROXY="direct"
并且git config --global
输出为:
url.file:///tmp/git/.insteadof=https://git.localhost/
protocol.file.allow=always
更新2:
go get
命令的详细输出:
GOFLAGS="-v -x" go get git.localhost/repo1
# get https://git.localhost/?go-get=1
# get https://git.localhost/repo1?go-get=1
# get https://git.localhost/?go-get=1: Get "https://git.localhost/?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
# get https://git.localhost/repo1?go-get=1: Get "https://git.localhost/repo1?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
go: unrecognized import path "git.localhost/repo1": https fetch: Get "https://git.localhost/repo1?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
英文:
I'm trying to simulate remote repository for Go dependency as local git repo. I'm aware of go mod edit -replace
etc., but for my use case I need Go command to fetch dependency from git repo locally.
To simulate it with minimal reproducible example, I created bare git repo:
# in /tmp/git/repo1
git init --bare
Then cloned the repo, created go project, and pushed it back:
# in /tmp/projects/
git clone file:///tmp/git/repo1
cd repo1
go mod init git.localhost/repo1
git add go.mod && git commit -m "init: go mod init localhost" && git push origin
Just in case, checked bare repo updated successfully:
# in /tmp/git/repo1
git cat-file -p $(cat refs/heads/master) | grep init
# init: go mod init localhost
Then I created "client" go project, updated git config and tried to fetch it using go get
:
# in /tmp/go-proj
go mod init example.com
git config --global url."file:///tmp/git/".insteadOf "https://git.localhost/"
go get git.localhost/repo1
But got this error:
go: unrecognized import path "git.localhost/repo1": https fetch: Get "https://git.localhost/repo1?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
Also, I tried to update GOPRIVATE
env and set git config allow=always for file
protocol:
export GOPRIVATE="git.localhost/*"
git config --global protocol.file.allow always
And checked git can clone this repo by using:
git clone https://git.localhost/repo1
# successfully cloned from bare repo
Is it possible to get dependency from local git bare repo using go get
?
Update:
Added GOPROXY
env, so now my go env
has:
GOPRIVATE="git.localhost/*"
GOPROXY="direct"
and git config --global
has:
url.file:///tmp/git/.insteadof=https://git.localhost/
protocol.file.allow=always
Update2:
Verbose output for go get
command:
GOFLAGS="-v -x" go get git.localhost/repo1
# get https://git.localhost/?go-get=1
# get https://git.localhost/repo1?go-get=1
# get https://git.localhost/?go-get=1: Get "https://git.localhost/?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
# get https://git.localhost/repo1?go-get=1: Get "https://git.localhost/repo1?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
go: unrecognized import path "git.localhost/repo1": https fetch: Get "https://git.localhost/repo1?go-get=1": dial tcp: lookup git.localhost on 127.0.0.1:53: no such host
答案1
得分: 1
以防万一这是问题,首先使用以下命令测试您的go get
命令:
export GOPROXY=direct
这样应该允许go get
从本地Git仓库获取依赖项而不会出现任何问题。
这应该是除了您的其他设置之外设置的,比如您的export GOPRIVATE="git.localhost/*"
和Git的insteadOf
指令。
OP在评论中补充道:
> 看起来go get
正在尝试通过http从依赖主机(在我的情况下是git.localhost)获取一些元数据,然后在go/pkg/mod/cache/vcs/{hash}
中创建git包仓库,然后使用git获取依赖代码,其中git应用了insteadOf
替换。
>
> 所以我打算创建一个简单的http服务器,以对http://git.localhost/?go-get=1 URL响应带有VCS、前缀和RepoRoot URL响应的元信息。
这确实是在“如何使go get与本地服务器上的存储库一起工作”中所说明的。
英文:
Just in case this is the issue, test your go get
command with first:
export GOPROXY=direct
That should allow go get
to fetch the dependency from the local Git repository without any issues.
That should be set in addition to your other settings, like your export GOPRIVATE="git.localhost/*"
and your Git insteadOf
directive.
The OP adds in the comments:
> Looks like go get is trying to fetch some meta data via http from dependency host (git.localhost in my case), then create package git repo in go/pkg/mod/cache/vcs/{hash}
and then fetch dependency code using git, where git applies isnteadOf
replace.
>
> So I'm going to try create simple http server to respond with meta information with VCS, Prefix and RepoRoot url response to http://git.localhost/?go-get=1 URL
This is indeed what is illustrated in "How can I make go get work with a repo on a local server".
答案2
得分: 1
为了解决这个问题,我启动了一个基本的HTTP Web服务器,用于处理go get
请求并返回带有<meta>
go-import标签的HTML页面。它指定了git仓库的位置为https://git.localhost/<repo-name>
,然后go get
使用git来获取这个仓库,并且insteadOf
git配置将https://git.localhost
替换为file:///
位置。此外,需要设置GOINSECURE="git.localhost/*
环境变量以使用http请求go-get请求。
这是我的服务器处理程序(带有子模块和语义版本支持):
package main
import (
"fmt"
"log"
"net/http"
"regexp"
"strings"
)
// 仓库名称:/repo /repo/module /repo/ /repo/submodule /repo/v2
var reRepo = regexp.MustCompile(`^/([a-zA-Z0-9_-]+)/?(?:.+)?$`)
func main() {
http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
repoParts := reRepo.FindStringSubmatch(r.URL.Path)
if len(repoParts) == 0 {
http.NotFound(w, r)
return
}
name := repoParts[1]
log.Printf("解析 %s => %s", r.URL.Path, name)
var sb strings.Builder
sb.WriteString("<html><head>")
sb.WriteString(fmt.Sprintf(`<meta name="go-import" content="git.localhost/%s git https://git.localhost/%s" />`, name, name))
sb.WriteString("</head></html>")
fmt.Fprint(w, sb.String())
}))
}
英文:
To solve this problem, I started primitive HTTP web server to return HTML page for go get
requests with <meta>
go-import tag. It specifies the location of git repository as https://git.localhost/<repo-name>
and then go get
uses git to fetch this repo and insteadOf
git config replaces https://git.localhost
with file:///
location. Also, GOINSECURE="git.localhost/*
environment is required to request go-get requests using http.
This is my server handler (with submodule and semver support):
package main
import (
"fmt"
"log"
"net/http"
"regexp"
"strings"
)
// repo names: /repo /repo/module /repo/ /repo/submodule /repo/v2
var reRepo = regexp.MustCompile(`^/([a-zA-Z0-9_-]+)/?(?:.+)?$`)
func main() {
http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
repoParts := reRepo.FindStringSubmatch(r.URL.Path)
if len(repoParts) == 0 {
http.NotFound(w, r)
return
}
name := repoParts[1]
log.Printf("Resolve %s => %s", r.URL.Path, name)
var sb strings.Builder
sb.WriteString("<html><head>")
sb.WriteString(fmt.Sprintf(`<meta name="go-import" content="git.localhost/%s git https://git.localhost/%s" />`, name, name))
sb.WriteString("</head></html>")
fmt.Fprint(w, sb.String())
}))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论