跳到主要内容

发布包到公共市场

Go 的「公共市场」不是单独上传中心仓,而是:公开 VCS 仓库 + 语义化 tag,再由默认代理 proxy.golang.org 拉取、校验,并在 pkg.go.dev 展示。别人用 go get your/module@vX.Y.Z 即可依赖。

本篇在「包与模块初识」「工程与依赖管理」之上,走通 可发布模块 → 打 tag → 进代理 / 文档站。

先说结论:发布物是 带版本号的模块源码快照(由 git tag 钉住),不是上传 wheel/sdist。同一 tag 推上远程后内容不可改——错了只能发新版本(或按规范 retract)。

和 Python / PyPI 的差别(心智模型)​

GoPython(PyPI)
公共入口仓库 URL ≈ 模块路径;代理缓存上传到索引站
版本来源git tag(如 v1.2.3)pyproject.toml 版本 + 上传
安装命令go get example.com/lib@v1.2.3pip install / uv add
文档浏览pkg.go.devpypi.org 项目页

发之前要齐什么​

项说明
公开仓库GitHub / GitLab 等;默认分支可克隆
模块路径go.mod 的 module 与仓库导入路径一致(如 github.com/you/lib)
可导入 API导出标识符(大写);不想被外部用的放 internal/
LICENSE / README许可证与说明;影响 pkg.go.dev 展示与合规
测试通过go test ./...;至少保证对外包可构建
go mod init github.com/you/example-lib # 路径按真实仓库写

本地练习可用假路径;要公开发布时,模块路径必须能被 go get 解析到该仓库(常见即 github.com/<user>/<repo>)。

最小可发布布局​

github.com/you/example-lib/
go.mod
go.sum # 有依赖时
LICENSE
README.md
example.go # package example(或子目录包)
example_test.go
# go.mod
module github.com/you/example-lib

go 1.22
// example.go
package example

// Hello 返回问候语。
func Hello(name string) string {
return "hello, " + name
}

注意:

  • 模块路径 决定别人的 import 前缀;改路径等于换模块身份
  • 仓库里可以有 cmd/ 放可执行入口;库代码与 main 分包,避免把 CLI 和库缠死
  • 仅本模块内部用的代码放 internal/,外部 go get 进不来

版本与 tag​

Go 模块版本遵循 语义化版本,tag 带 v 前缀:

git tag v0.1.0
git push origin v0.1.0
# 或:git push origin --tags
版本含义(约定)
v0.x.y尚不稳定,允许破坏性变更
v1.x.y稳定 API;破坏性变更应进下一主版本
v2.0.0 起模块路径须带主版本后缀,如 module github.com/you/lib/v2,import 也要 /v2

预发布可用 v1.2.3-rc.1 等;正式依赖更常见钉稳定 tag。

发版前建议:

go test ./...
go vet ./...
go mod tidy

确认 go.mod / go.sum 已提交,再打 tag。

让代理与文档站「看见」你​

推送 tag 后,可主动请求默认代理拉取(加速出现在缓存与 pkg.go.dev):

# 用代理解析该版本(会触发拉取与校验)
GOPROXY=https://proxy.golang.org GO111MODULE=on \
go list -m github.com/you/example-lib@v0.1.0

也可打开:

https://pkg.go.dev/github.com/you/example-lib@v0.1.0

若暂未出现,稍等或点站内「Request」类入口(以 pkg.go.dev 当前 UI 为准)。校验由 sum.golang.org 提供;他人安装时会核对 go.sum。

他人依赖:

go get github.com/you/example-lib@v0.1.0
import "github.com/you/example-lib"

主版本升级(v2+)​

破坏性变更进 v2 时:

  1. go.mod 改为 module github.com/you/example-lib/v2
  2. 本仓库内 import 同步加 /v2
  3. 打 tag v2.0.0(路径与主版本一致)

v0/v1 的模块路径不加 /v1;从 v2 起必须加。这与「只改 tag、不改 path」不同——漏改 path 会导致别人装错或装不上。

发错了怎么办​

情况做法
tag 内容有 bug不要强改已推送的 tag;发 v0.1.1 / v1.2.4
严重错误版本需阻止使用在 go.mod 使用 retract,再发一个含 retract 声明的新版本
模块路径写错等于新模块;旧路径上的版本仍按原路径存在
# go.mod 示例(在后续版本中声明)
retract v0.1.0 // 说明原因

发布检查表​

  1. module 路径与公开仓库一致,克隆 URL 可访问
  2. go test ./... / go build ./... 通过;go mod tidy 已做
  3. LICENSE、README、导出 API 的文档注释就绪
  4. tag 形如 vX.Y.Z,且该 tag 未在远程用过不同内容
  5. v2+ 已改模块路径与 import
  6. 推送 tag 后用 go list -m ...@vX.Y.Z 或 pkg.go.dev 确认
  7. 私有模块不要指望默认公共代理;用 GOPRIVATE / 公司代理(本篇只覆盖公共市场)

常见坑​

现象常见原因
go get 找不到版本未推 tag、tag 无 v 前缀、仓库私有
v2 装上后 import 对不上模块路径未加 /v2,或调用方仍写旧 path
pkg.go.dev 很久不更新代理尚未拉取;主动 go list -m 或站内请求
改了历史 tag 别人校验失败sumdb 已记录旧哈希;只能发新版本
把应用和库揉在一个 main 包外部只能当程序用;库应独立非 main 包

要点​

  1. 公共市场 ≈ 公开仓库 + v* tag + 默认模块代理 / pkg.go.dev
  2. go.mod 的 module 路径必须对准仓库
  3. tag 不可当可变发布物;错了就升版本(必要时 retract)
  4. v2+ 必须改模块路径后缀
  5. 日常加依赖、整理模块仍见「工程与依赖管理」