惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
月光博客
月光博客
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
O
OpenAI News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Know Your Adversary
Know Your Adversary
Last Week in AI
Last Week in AI
S
Securelist
Engineering at Meta
Engineering at Meta
博客园 - 司徒正美
P
Privacy & Cybersecurity Law Blog
T
Tailwind CSS Blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
Scott Helme
Scott Helme
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
C
Cisco Blogs
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
小众软件
小众软件
U
Unit 42
Microsoft Azure Blog
Microsoft Azure Blog
Hacker News: Ask HN
Hacker News: Ask HN
Hugging Face - Blog
Hugging Face - Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
P
Proofpoint News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
Lohrmann on Cybersecurity
IT之家
IT之家
Security Archives - TechRepublic
Security Archives - TechRepublic
I
InfoQ
S
Security @ Cisco Blogs
Webroot Blog
Webroot Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Full Disclosure
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Jina AI
Jina AI
Cyberwarzone
Cyberwarzone
人人都是产品经理
人人都是产品经理
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
B
Blog RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research

Go 编程语言

[工业边缘网关] EdgeX 更新啦,增加了 MCP,可以被 AI 接管了,可以让 AI 控制物理世界啦 - V2EX [工业边缘网关] EdgeX 更新啦 上线了官网 顺便更新版本 v0.10.0 - V2EX 有了 Agent,后台脚手架是该退场,还是变成约束层? - V2EX 强兼 Claude Code:左 DeepSeek V4,右 Kimi K3 - V2EX [边缘计算] 想借助 AI 来开发 边缘网关接入 AI 解决设备通信 不知道有没有需求 - V2EX [Go]工业边缘计算网关 edgex 业余时间独立开发 持续更新半年咯 求个 star - V2EX eget:不用等中央仓库,直接安装 GitHub 和任意下载站的工具 - V2EX gookit/gcli v3.8:新增支持共享选项、文档生成和参数重排 - V2EX V2EX 我开源了一款极简的 P2P 文件传输与 VPN 工具 (Win/Mac/ Linux /Android) - V2EX gookit/gcli v3.5.0 发布 - 简单易用、功能丰富的 Go 命令行应用与工具库 - V2EX 用 Go gRPC 信令对接 Android WebRTC:大家一般怎么划分网关和客户端边界? 在服务端用 Pion + FFmpeg + RNN 做 WebRTC 通话降噪,值得吗? 这两种 lint 报错场景, v 友们一般怎么处理 - V2EX tikrok 的部分来时路 tikrok 第 7 代微服务重构: Golang 微服务 grpc 接口与服务实现隔离方案 写了个 Go 库:在 TCP 应用协议开始前做认证,也支持端口敲门 Tikrok v6.0 新的生产级架构,成本不变,但是部署复杂略有增加 go 打包的二进制程序怎么反编译 [边缘计算开源] 工业数据采集网关 版本更新 用 golang 写了,一套面向个人音乐资产的本地优先音乐系统 做了个 Go 的 MCP Server 框架,一行代码把 Gin API 接入 AI - V2EX 写了个 Go 库解决 LLM 流式输出断线重连的问题 - V2EX Tikrok v5.0 新的的底层实现 - V2EX OpenTelemetry 分布式追踪中的回溯采样:削减 60% 尾部采样成本 - V2EX 求推荐一个 go 里运行 js 的方案 - V2EX [边缘计算] 基于 GO 的采集网关持续更新啦 - V2EX [边缘计算开源] 基于 go 写了个独立运行的工业数据采集网关 后续阶段应该如何调整 - V2EX 然后 go-kratos 不怎么活跃了,连最火的 skills 都不搞, github 也没什么人回复了 - V2EX Excelize 开源基础库发布 2.10.1 版本更新 phper 转 go 最好的 web 框架是 goframe 吗? - V2EX A Visual Studio Code extension that displays the disk size of Go module dependencies in go.mod files. - V2EX miglite: Go 极简高效的数据库迁移工具 - V2EX 每秒万级 Tick 震荡:高频行情分发,该选 Golang 的并发原生还是 Rust 的极致性能? - V2EX 给 netcat 引入了 P2P 穿透、多路复用、强加密以及内置服务模块,并且完全开源 - V2EX 使用 "go.inlayHints.parameterNames": true 在 vscode 中开启类似 goland 的参数提示 - V2EX 下面代码中 f()会被重复执行吗?大佬帮忙解答一下~ - V2EX sublimetext 开发 GO 使用体验怎么样 - V2EX [开源] 将 react 的 hooks 和 组件化思路带入 go 的 TUI 开发。 - V2EX gocar 0.2.0 版本:新增自定义命令功能,实现真正的 go 的 cargo - V2EX go 新手,求问导入包失败问题 - V2EX 之前写的, JSR-310 风格的时间日期库, 1.0 了 - V2EX 为了方便学习 go, 使用 go 做了一个命令行版本的 go playground, 代码直接一键运行, 一键编译 - V2EX 虚心请教 Go 前辈们,关于入行 - V2EX 关于 Go 的工程经验 - V2EX 微信开发框架开源,基于 Go+Wails3+React - V2EX Golang 实现的开源 NVR 支持 GB28181 & ONVIF 啦 - V2EX Go 工具库 gookit/goutil v0.7.2 发布:增强功能与修复,提升开发体验 - V2EX go-carbon v2.6.15 正式版发布,已被 docker 官方组织使用 - V2EX 如何用 3–5 个高效问题快速识别 Golang 开发者的技术素养? - V2EX 有没有 go 的 ai 应用项目学习学习 - V2EX Go 环境版本管理用哪个- -有点疑惑 - V2EX Goland 下的通义千问不能选择模型,VScode 下面的通义千问可以选择模型 - V2EX 新手入门求指导 - V2EX 看 Go 的时间库不顺眼很久了,所以从别的语言里抄了一个 - V2EX go-dongle v1.2.0 发布,新增 SM2 非对称椭圆曲线加密算法支持 - V2EX Wails2+Vue3 本地的绑定文件和 Vite 上的不一致 - V2EX go 返回错误的时候, 返回的值应该可用吗 - V2EX Go 入门基础课(2025 Golang) - V2EX goland 中如何 debug wails - V2EX 日期函数获取上一个月 bug, 在一些特殊日子才出现,比如今天 10-31 - V2EX go-carbon v2.6.14 发布,一个轻量级、语义化的 golang 时间处理库 - V2EX goroutine 到底算不算一种 coroutine 的实现? - V2EX 为什么不用 gRPC-Go: VictoriaTraces 中实现 OTLP/gRPC 的幕后故事 - V2EX go 最新版的 map 并发读是安全的吗。 - V2EX 请问一下 golang 下有什么成熟稳定的串口通讯包? - V2EX golang.org/x/sync/syncmap 被 struct 裹挟时 使用前为什么必须为每个键初始化 不然取值得到 nil go-dongle v1.1.7 发布,新增 SM4 国密分组对称加密算法支持 在开发接口的过程中,如何快速验证结果? - V2EX go-carbon v2.6.13 发布,一个轻量级、语义化的 golang 时间处理库
构建时自动注入版本号:从 Git tag 到 Go 可执行文件 - V2EX
breezeStrak · 2026-07-16 · via Go 编程语言

在发布一个 Go 项目时,我们总希望知道当前跑的是哪个版本、哪次提交、哪个分支。最原始的做法是手动改代码里的版本号,但这种方式很容易忘记更新,导致线上版本和实际代码对不上。

goddd 的做法是:版本号只写在 Git tag 里,构建时由 Makefile 自动读取并注入到程序中。这样只要你会打 tag ,就不用再操心版本号的事情。

1. 整体思路

整个流程可以拆成三步:

  1. 用 Git tag 标记版本:例如 v1.0.0v1.2.3,这是唯一的版本来源。
  2. Makefile 自动计算版本字符串:根据最近的 tag 和距离它的提交次数,生成类似 v1.0.5 这样的版本号。
  3. go build 构建时注入:通过 -ldflags -X 把版本号写进 Go 程序的变量里。

下面我们就一步步拆开来看。

2. 先在代码里留出“注入位”

打开项目根目录下的 main.go,可以看到这样一段变量声明:

package main

var (
	buildVersion = "0.0.1" // 构建版本号
	gitBranch    = "dev"   // git 分支
	gitHash      = "debug" // git 提交点哈希值
	release      string    // 发布模式 true/false
	buildTime    string    // 构建时间戳
)

这几个变量有两个关键点:

  • 它们都是 var 声明的,不能是 const。因为 go build-ldflags -X 只能在链接阶段修改变量,常量是无法被修改的。
  • 它们都位于 main下。Makefile 里注入时用的也是 main.buildVersion 这种写法。

main() 函数里,这些变量又被用到了几个地方:

func main() {
	// ... 初始化配置

	bc.Runtime.BuildVersion = buildVersion

	// 通过 expvar 暴露出去,方便监控和调试
	expvar.NewString("version").Set(buildVersion)
	expvar.NewString("git_branch").Set(gitBranch)
	expvar.NewString("git_hash").Set(gitHash)
	expvar.NewString("build_time").Set(buildTime)

	// 同时作为数据库迁移的版本依据
	versionapi.DBVersion = buildVersion
	versionapi.DBRemark  = gitBranch + "_" + gitHash

	app.Run(&bc)
}

也就是说,只要构建时把 buildVersion 等变量改掉,程序内部所有依赖版本号的地方都会自动生效,不需要手动再去改其他文件。

3. Makefile 里怎么算出版本号?

项目的 Makefile 中专门有一块 VERSION 逻辑,负责从 Git 历史里提取版本信息:

点击查看 Makefile 版本号计算逻辑

看不懂 Makefile 没关系,我们把它翻译成大白话:

  • RECENT_TAG:找到当前提交上最近的 Git tag ,比如 v1.0.1
  • COMMITS:数一数从那个 tag 之后到现在,一共又提交了多少次。
  • GIT_VERSION_MAJOR / MINOR / PATCH:把 tag 拆成主版本号、次版本号、修订号。
  • FINAL_PATCH:把修订号加上后面的提交次数,得到最终的修订号。
  • VERSION:把三部分拼起来,例如 v1.0.12

如果没有打过任何 tag ,默认从 v0.0.0 开始,提交次数直接加到修订号上,变成 v0.0.15 这种形式。

你可以直接运行:

make info

它会输出当前计算出来的版本号、分支、提交哈希等信息,方便检查是否正确。

4. 构建时把版本号“塞”进程序

版本号算好了,接下来就要在编译时写进程序。关键命令在 Makefilebuild/local 目标里:

## build/local: 构建本地应用
.PHONY: build/local
build/local:
	$(eval dir := $(BUILD_DIR_ROOT)/$(GOOS)_$(GOARCH))
	@echo 'Building $(VERSION) $(dir)...'
	@rm -rf $(dir)
	@CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) go build \
		-trimpath \
		-ldflags="-s -w \
			-X main.buildVersion=$(VERSION) \
			-X main.gitBranch=$(BRANCH) \
			-X main.gitHash=$(HASH_AND_DATE) \
			-X main.buildTimeAt=$(shell date +%s) \
			-X main.release=true \
			" -o=$(dir)/bin ./main.go
	@echo '>>> OK'

这里最重要的是 -ldflags="-X main.buildVersion=$(VERSION)" 这一行。

-X 是 Go 链接器的一个参数,作用是:在生成可执行文件时,把指定包里的某个字符串变量的值替换掉。写法是:

-X 包名.变量名=新值

因为我们注入的是 main 包里的变量,所以写成 main.buildVersionmain.gitBranch 等。

注意:-s -w 是用来裁剪调试信息的,可以让生成的二进制文件更小,和版本注入本身无关。

5. 实际使用流程

假设你刚完成了一次功能开发,准备发版:

第一步:打 tag

git tag -a v1.2.0 -m "发布 1.2.0"
git push origin v1.2.0

建议 tag 名统一用 v 开头,例如 v1.2.0,这样 Makefile 里的解析规则才能正确工作。

第二步:构建

make build/linux

构建完成后,二进制文件会出现在 build/linux_amd64/bin 目录下。

第三步:验证版本号

程序启动后,你可以通过接口查看当前版本:

curl http://localhost:8080/health

返回值类似:

{
  "version": "v0.0.159",
  "start_at": "2026-07-15T11:13:27.780618606+08:00",
  "git_branch": "dev",
  "git_hash": "c125b7f-260715"
}

如果通过配置开启了 pprof ,也可以访问:

curl http://localhost:8080/debug/vars

在里面能看到 versiongit_branchgit_hashbuild_time 等字段。

这是最常见的情况:你正在开发中,当前提交本身还没有 tag 。比如最近的 tag 是 v1.0.0,从那以后你又提交了 5 次,那么 make info 会显示:

version: v1.0.5

也就是说,中间的开发版本会自动以“最近的 tag + 提交次数”的形式呈现。等到你正式发布时再打一个 v1.1.0v1.0.5 的 tag 即可。

7. 常见坑和注意事项

  1. 变量必须是 var,不能是 const -ldflags -X 只能修改变量,常量注入不了。

  2. 变量必须是字符串类型 虽然 release 看起来是布尔含义,但它在 main.go 里声明的是 string,后续再用 strconv.ParseBool 去解析。

  3. tag 要推送 只本地打 tag 不推送到远程,CI/CD 构建时就读不到。发布时记得 git push origin <tag>

  4. Windows 下没有 bc 命令 Makefile 里特意用 awk 代替了 bc,就是为了兼容 Windows 的 Git Bash 环境。

  5. 注入的是 main 包变量 如果你想给非 main 包的变量注入值,-X 后面要写完整的包路径,例如 -X github.com/ixugo/goddd/internal/conf.buildVersion=xxx

8. 这样做的好处

  • 版本号和代码解耦:再也不用每次发版都改代码里的字符串。
  • 版本号有迹可循:看到 v1.0.5 就能知道它基于 v1.0.0 之后第 5 次提交。
  • 构建产物可追踪:每个二进制文件都自带分支、commit hash 、构建时间,出了问题方便定位。
  • 和 CI/CD 天然适配:流水线里只需要 git tag + make build/linux 两步。

关于 goddd

goddd 是一个 AI 驱动的 Go 语言脚手架,基于领域驱动设计( DDD )思想搭建,提供了一套适合中小项目快速启动的工程结构和最佳实践。

如果你想了解更多细节,可以访问: