Go 项目版本号自动管理,并发布 git tag

更新日期: 2025-12-16 阅读次数: 59 字数: 916 分类: Git

最近使用 Golang 开发的网站项目比较多,所以把一些常用的功能写成了一个公共库,放在 GitHub 上,方便在其他项目中通过 go get 使用。 这个公共库的版本号需要通过 git tag 来管理。每次发布新版本时,都会在 git 上打一个 tag,然后在其他项目中通过 go get 来获取最新版本。例如:

go get github.com/sunzhongwei/hades@v1.0.2

手动打 git tag 的烦恼

手动设置很容易漏掉 v 前缀,例如,v1.0.2 一不小心就写成了 1.0.2。 这个问题还不容易被察觉 🥲,在其他项目中需要 go get 新版本时,如果还继续使用 v 开头的版本号,就会收到提示找不到对应的版本号。 排查半天才发现是漏掉了 v 前缀。

第二个问题是,VSCode 中通过 GUI 界面打 tag,操作很繁琐。最后还需要点一堆按钮才能找到 Push Tags 的选项。

所以,我决定搞一个自动化的方案,来解决这两个问题。

方案一(采用)

我参考 gin 的做法,在项目中创建一个 version.go 文件,里面定义版本号常量。 例如 version.go 文件:

package hades

const Version = "v1.0.3"

然后在 Makefile 中实现一个命令,自动读取当前 version.go 文件中的版本号,然后在当前版本号上增加一个小版本号。例如,当前是 v1.0.1, 那么下一个小版本号就是 v1.0.2。把新版本号更新到 version.go,并且 commit ,然后添加 git tag,并将 git tag push 到 remote。

让 AI 实现了这段 Makefile 代码,具体参考:

https://github.com/sunzhongwei/hades/blob/main/Makefile

SHELL := /bin/bash

.PHONY: tag
tag:
	@current=$$(grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' version.go | head -n1 | tr -d 'v'); \
	if [ -z "$$current" ]; then echo "version not found in version.go"; exit 1; fi; \
	maj=$$(echo $$current | cut -d. -f1); \
	min=$$(echo $$current | cut -d. -f2); \
	patch=$$(echo $$current | cut -d. -f3); \
	newpatch=$$(expr $$patch + 1); \
	new="v$$maj.$$min.$$newpatch"; \
	printf "Bump: v%s -> %s\n" "$$current" "$$new"; \
	sed -E -i.bak 's/(const Version = ")([^"]+)(")/\1'"$$new"'\3/' version.go; \
	git add version.go; \
	git commit -m "chore(release): $$new"; \
	git push origin HEAD; \
	git tag -a "$$new" -m "release $$new"; \
	git push origin "$$new"; \
	rm -f version.go.bak

这样就只需要一行命令,就能自动升级版本号了

make tag

命令说明:

grep 是提取 version.go 文件中的版本号:

$ grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' version.go | head -n1 | tr -d 'v'
1.0.3

sed 命令是更新 version.go 文件中的版本号:

因为 Makefile 用了 sed 的 -i.bak 选项:sed -i.bak ... version.go 会在就地修改前把原文件复制一份为 version.go.bak 作为备份,修改失败或需要回退时可以用备份恢复。随后通过 rm -f version.go.bak 删除该备份。这样写也提高了在 macOS/BSD(需要 -i 带扩展名)和 GNU sed 之间的兼容性。

看看效果

本地的 git 历史:

本地的 git 历史

github remote 端的 tags:

github remote 端的 tags

方案二(未采用)

第二个方案是,使用 git tag 命令,来或者最新的 tag,然后在这个 tag 的基础上增加小版本号,生成新的 tag。

例如,按语义化版本号排序(v1.2.3 格式)

$ git tag --sort=-version:refname | head -1
v1.0.2

然后把这个 tag 解析成主版本号、次版本号和小版本号,增加小版本号,生成新的 tag。

但是,我担心这个方案不够直观。我倾向于能够直接在代码中看到当前版本号是什么,而不是需要通过 git 命令去查询最新的 tag。 如果出现不兼容性的改动,也能直接通过判断代码中的版本号,来做兼容性处理。

关于作者 🌱

我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式