项目版本号管理与发布策略
· 阅读需 6 分钟
本文介绍项目版本号管理的最佳实践,包括语义化版本规范、版本号演进流程、正式版本发布策略、以及如何在不同技术栈中实现版本管理自动化。涵盖从开发环境到生产环境的完整版本控制方案。
1. 版本号规范
项目遵循 语义化版本(Semantic Versioning 2.0.0) 规范:
MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]
- MAJOR(主版本号):存在不兼容的 API 或重大功能变更时递增
- MINOR(次版本号):新增功能且兼容旧版本时递增
- PATCH(修订号):仅做向后兼容的问题修复时递增
- PRERELEASE(预发布号):标识测试版、候选版(可选)
- BUILD(构建号):构建或提交标识(可选)
示例:
| 类型 | 示例 | 说明 |
|---|---|---|
| 开发版本 | 1.0.0-dev.20251103 | 每日构建或开发测试版本 |
| 内部测试版 | 1.0.0-alpha.5 | 功能不完整,仅供内部使用 |
| 公测版 | 1.0.0-beta.3 | 功能完整但仍可能存在问题 |
| 候选版 | 1.0.0-rc.1 | 即将发布的版本,若无问题即转正 |
| 正式版 | 1.0.0 | 对外正式发布版本 |
| 修复版 | 1.0.1 | 仅修复问题 |
| 功能更新 | 1.1.0 | 新增兼容性功能 |
| 不兼容更新 | 2.0.0 | 有重大变更或接口修改 |
2. 版本号演进流程
版本从开发到发布的生命周期:
dev → alpha → beta → rc → release
| 阶段 | 命名规则 | 使用场景 |
|---|---|---|
| 开发阶段 | x.y.z-dev.N | 开发环境构建,内部自测 |
| 内部测试 | x.y.z-alpha.N | 内部 QA 测试版本 |
| 公测阶段 | x.y.z-beta.N | 外部试用或小范围测试 |
| 发布候选 | x.y.z-rc.N | 准备上线,若无阻塞问题即发布为正式版 |
| 正式发布 | x.y.z | 稳定版本,公开分发 |
| 后续修复 | x.y.(z+1) | Bug 修复或安全更新 |
3 正式版本发布策略
3.1 预发布版本到正式版的转化
当 x.y.z-rc.N 测试通过后,发布脚本自动去掉 -rc.N 后缀,生成正式版本:
1.0.0-rc.3 → 1.0.0
2. 不跳号策略
版本号递增必须连续,禁止跳过或回退版本号:
✅:1.0.0 → 1.0.1 → 1.1.0 → 2.0.0
❌: 1.0.0 → 2.0.5(中间版本不存在)
3. 版本号来源
3.1 不同技术栈的版本存储位置
基础版本号存储位置因项目技术栈而异:
| 技术栈 | 版本号存储位置 | 常用工具 |
|---|---|---|
| Node.js | package.json 中的 version 字段 | standard-version, semantic-release |
| Python | pyproject.toml、setup.py 或 __version__.py | bump2version, poetry, setuptools-scm |
| Java (Maven) | pom.xml 的 <version> | Maven Versions Plugin |
| Java (Gradle) | build.gradle 或 gradle.properties | Gradle version task |
| Rust | Cargo.toml 的 package.version | cargo bump |
| Go | Git tag(模块版本由 tag 决定) | git tag |
| .NET | *.csproj 或 Directory.Build.props | GitVersion |
| Android | build.gradle 的 versionName/versionCode | Gradle task |
| iOS | Info.plist 的 CFBundleShortVersionString | agvtool, fastlane |
| 容器/Helm | Chart.yaml 的 version/appVersion | helm package |
| 通用方案 | 项目根目录的 VERSION 文件 | 自定义脚本 |
3.2 单一来源策略
版本号必须有且仅有一个权威来源,所有其他位置的版本号都从该来源派生或校验一致。
策略 A:文件为来源(推荐用于应用/服务)
- 版本号定义在清单文件中(如
package.json、pom.xml、Cargo.toml、VERSION) - 发布流程:更新文件版本 → 提交代码 → 打 Git tag → 发布
- CI 负责校验 Git tag 与文件版本一致
策略 B:Tag 为来源(常见于库/SDK、Go 模块)
- 版本号由 Git tag(如
v1.2.3)决定 - 发布流程:打 Git tag → CI 从 tag 解析版本 → 注入到构建产物
- 适用场景:Go 模块、Python + setuptools-scm、版本不需内嵌到应用的库
核心原则
- 发布必须打 Git tag 作为锚点
- 禁止文件版本与 tag 版本漂移
- CI 在构建时强制校验版本一致性
3.3 CI 校验示例
策略 A:文件为来源,校验 tag 一致性
#!/bin/bash
set -e
# 从文件读取版本(根据项目类型自动检测)
if [ -f "package.json" ]; then
FILE_VERSION=$(node -p "require('./package.json').version")
elif [ -f "Cargo.toml" ]; then
FILE_VERSION=$(grep -m1 '^version' Cargo.toml | cut -d'"' -f2)
elif [ -f "VERSION" ]; then
FILE_VERSION=$(cat VERSION)
else
echo "Error: No version file found" >&2
exit 1
fi
# 如果存在 Git tag,校验一致性
TAG_VERSION=${GIT_TAG:-$(git describe --tags --exact-match 2>/dev/null || true)}
if [ -n "$TAG_VERSION" ]; then
TAG_VERSION=${TAG_VERSION#v} # 移除 'v' 前缀
if [ "$FILE_VERSION" != "$TAG_VERSION" ]; then
echo "❌ Version mismatch: file=$FILE_VERSION, tag=$TAG_VERSION" >&2
exit 1
fi
echo "✅ Version validated: $FILE_VERSION"
fi
export BASE_VERSION="$FILE_VERSION"
策略 B:Tag 为来源,注入到构建
#!/bin/bash
set -e
# 从 Git tag 获取版本
TAG_VERSION=${GIT_TAG:-$(git describe --tags --abbrev=0)}
BASE_VERSION=${TAG_VERSION#v} # 移除 'v' 前缀
# 导出环境变量供后续构建使用
export BASE_VERSION
echo "BASE_VERSION=$BASE_VERSION"
# 可选:写入到构建产物(如生成 version.txt)
echo "$BASE_VERSION" > version.txt
3.4 完整版本号生成示例
CI/CD 根据基础版本和构建环境,自动生成带预发布信息的完整版本号:
| 环境 | 基础版本 | 生成规则 | 最终版本号 |
|---|---|---|---|
| 开发环境 | 1.0.0 | ${BASE}-dev.${DATE}.${BUILD_NUM} | 1.0.0-dev.20251103.123 |
| 测试环境 | 1.0.0 | ${BASE}-beta.${BUILD_NUM} | 1.0.0-beta.5 |
| 预发布 | 1.0.0 | ${BASE}-rc.${BUILD_NUM} | 1.0.0-rc.1 |
| 生产环境 | 1.0.0 | ${BASE}(仅正式版打 tag) | 1.0.0 |
4. 自动生成规则(Jenkins/CI)
#!/bin/bash
set -e
BASE_VERSION=$(cat VERSION)
BUILD_DATE=$(date +%Y%m%d)
BUILD_NUMBER=${BUILD_NUMBER:-0}
case "$BUILD_ENV" in
dev)
VERSION_FULL="${BASE_VERSION}-dev.${BUILD_DATE}.${BUILD_NUMBER}"
;;
test)
VERSION_FULL="${BASE_VERSION}-beta.${BUILD_NUMBER}"
;;
rc)
VERSION_FULL="${BASE_VERSION}-rc.${BUILD_NUMBER}"
;;
prod)
VERSION_FULL="${BASE_VERSION}"
;;
*)
echo "Unknown BUILD_ENV: $BUILD_ENV"
exit 1
;;
esac
echo "Final version: ${VERSION_FULL}"
5. Git 标签规范
| 类型 | Tag 示例 | 说明 |
|---|---|---|
| Alpha 测试版 | v1.0.0-alpha.3 | 内部测试 |
| Beta 公测版 | v1.0.0-beta.2 | 公测阶段 |
| RC 候选版 | v1.0.0-rc.1 | 最终预发布 |
| 正式发布版 | v1.0.0 | 对外版本 |
6. 版本号管理建议
- 不直接使用测试版号作为正式版
- 构建号自动生成,不手动递增数字
- 每个版本必须有 Git tag
- 应用 About 页面或 API 返回中应展示版本号
- 仅在必要时增加主版本号
7. 示例版本演进图
0.9.0-alpha.1
0.9.0-alpha.2
0.9.0-beta.1
0.9.0-beta.2
1.0.0-rc.1
1.0.0
1.0.1
1.1.0
2.0.0
8. 总结
| 阶段 | 示例版本号 | 是否公开 | 自动生成 | 用途 |
|---|---|---|---|---|
| 开发 | 1.0.0-dev.20251103 | 否 | ✅ | 内部开发调试 |
| 内测 | 1.0.0-alpha.5 | 否 | ✅ | QA 内部测试 |
| 公测 | 1.0.0-beta.2 | 可选 | ✅ | 小范围用户测试 |
| 候选 | 1.0.0-rc.1 | 否 | ✅ | 上线前最后验证 |
| 正式 | 1.0.0 | ✅ | ❌ | 最终公开发布 |
| 修复 | 1.0.1 | ✅ | ✅ | Bug 修复 |