项目在完成后往往都需要版本化, 而Golang项目往往交付的是编译过后的二进制包, 如何通过二进制包知道项目的版本, 就像docker的version命令一样楠?
为什么需要版本管理
版本管理主要用于对运行程序的版本追踪,从而可以管理线上服务的运行版本,避免各个版本的服务程序混淆.这里通常的做法为在程序中埋入版本标志,同时该版本号会对应到git上的tag或release版本.从而对线上服务更改有一个更全面的信息说明。
比如docker的版本信息:
maojun@maojun-mbp $ docker version
Client:
Version: 17.09.0-ce
API version: 1.32
Go version: go1.8.3
Git commit: afdb6d4
Built: Tue Sep 26 22:40:09 2017
OS/Arch: darwin/amd64
...
GUN风格版本命名方式和规则
这里将介绍基于GNU风格的一种版本命名方式, 这也是当今主流的版本命名方式, 很多开源项目的版本命名都遵循此风格。GUN风格版本命名风格:
Major_Version_Number.Minor_Version_Number[.Revision_Number[.Build_Number]]
主版本号.子版本号[.修正版本号[.编译版本号]]
示例 : 1.2.1, 2.0, 5.0.0.build-13124
- Major: 具有相同名称但不同主版本号的程序集不可互换。例如,这适用于对产品的大量重写,这些重写使得无法实现向后兼容性。
- Minor: 如果两个程序集的名称和主版本号相同,而次版本号不同,这指示显著增强,但照顾到了向后兼容性。例如,这适用于产品的修正版或完全向后兼容的新版本。
- Revision: 名称、主版本号和次版本号都相同但修订号不同的程序集应是完全可互换的。这适用于修复以前发布的程序集中的安全漏洞。
- Build: 内部版本号的不同表示对相同源所作的重新编译。这适合于更改处理器、平台或编译器的情况。版本号的变化一般遵循如下规则:
- 项目初版本 : 版本号可以为 0.1 或 0.1.0, 也可以为 1.0 或 1.0.0.
- 修正版本号增加: 当项目在进行了局部修改或 bug 修正时,主版本号和子版本号都不变,修正版本号加1.
- 子版本号增加 : 当项目在原有的基础上增加了部分功能时,主版本号不变,子版本号加 1,修正版本号复位为 0,因而可以被忽略掉.
- 主版本号增加 : 当项目在进行了重大修改或局部修正累积较多,而导致项目整体发生全局变化时.
- 编译版本号变化 : 编译版本号一般是编译器在编译过程中自动生成的,我们只定义其格式,并不进行人为控制
如何埋入版本信息
写C/C++代码时,可以在代码中预定义一些版本宏定义,然后再编译时从外部传入数据作为版本号, golang代码不支持宏定义, 但是go build时提供了一个与之相似的功能参数:
-ldflags 'flag list'
arguments to pass on each go tool link invocation.
然后查看go tool link的相关文档:
-X importpath.name=value
Set the value of the string variable in importpath named name to value.
Note that before Go 1.5 this option took two separate arguments.
Now it takes one argument split on the first = sign.
按照文档中的说明应该是在build时,通过-ldflags设定linker的参数。然后再通过linker的-X来修改指定路径下面的变量值
package main
import (
"fmt"
)
var (
VERSION
)
func main() {
fmt.Printf("Version:[%s]\n", VERSION)
}
编译时传入变量:
$ go build -ldflags "-X main.VERSION=v1.0.0-alpha1" main.go
$ ./main
Version:[v1.0.0-alpha1]
最终样例
如果我们直接在项目入口文件处埋入版本信息, 对项目入口侵入太大, 因此你会看到一些好的开源项目下都有一个专门的version包, 由它来负责接收埋入的版本信息。
最终示例请参考: Golang程序版本管理代码示例
maojun@maojun-mbp $ ./version-example -v
Version : v0.0.1-alpha.0
Build Time: 2017-11-19 23:28:12
Git Branch: master
Git Commit: 83de09af3f96007726edd5b308ed989476b9f358
Go Version: go1.9 linux/amd64