如何使用 git tags 或其他机制区分 test/dev/prod 发布版本?
Git 标签可以标记发布版本,但不能用来筛选、组合提交,也不能自动从发布包中排除测试代码。建议将测试代码和业务代码保存在同一个仓库中,通过构建或打包规则决定交付哪些文件。标签用于标记版本,部署配置用于区分 dev/test/prod 环境。
为什么不能通过标签筛选测试提交?
git checkout 没有用于筛选提交的 --tag 参数,因此不支持下面的命令:
git checkout release-2016-01 --tag test-code
Git 标签通常指向一个特定的 commit。每个 commit 记录的是当时完整的项目快照,检出标签时,得到的就是该版本的文件状态。
例如,有这样一段提交历史:
A:添加业务代码
B:添加测试代码,打标签 test-code
C:修复业务问题,打标签 v1.2.0
只要后续没有删除测试文件,检出 v1.2.0 时,B 中加入的测试代码就仍然存在。Git 不会根据 B 的标签决定这些文件是否进入发布包。
同一仓库中的同名标签只能指向一个目标,所以 test-code 不能像分类标记一样反复贴在多个提交上。即使分别给测试提交创建标签,也无法按标签过滤项目内容。
在构建和打包时排除测试代码
可以先将业务代码和测试代码放在不同目录中:
project/
├── src/
├── tests/
├── .travis.yml
└── 构建与打包配置
再让 CI 执行以下步骤:
- 检出待发布的 commit,安装运行和测试所需的依赖。
- 执行测试,失败时停止发布。
- 构建发布产物,通过打包配置只包含运行所需的文件。
- 检查产物内容,并尽可能针对实际产物执行安装、启动或集成测试。
- 保存通过验证的产物,供后续部署使用。
具体配置取决于项目语言和构建工具。编译型项目可以让测试代码只参与测试目标;解释型项目可以在包文件清单中排除 tests/,并将测试框架列为开发依赖。构建 Docker 镜像时,可以只复制构建结果和运行所需的依赖。
如果测试代码混在业务源码中,就需要调整代码组织或构建配置,仅排除 tests/ 目录还不够。打包时也可能误删运行所需的文件,因此,只测试源码无法确认发布包是否完整。
如果发布的是源码压缩包,可以使用 git archive
如果需要从仓库生成不含测试目录的源码包,可以在仓库根目录的 .gitattributes 中配置:
/tests export-ignore
/.travis.yml export-ignore
提交这份配置,并确保发布标签指向的版本包含它,然后生成压缩包:
git archive \
--format=tar.gz \
--prefix=myapp-1.2.0/ \
--output=myapp-1.2.0.tar.gz \
refs/tags/v1.2.0
生成的归档文件会排除仓库根目录下的 tests 目录和 .travis.yml。可以用以下命令检查归档清单:
tar -tzf myapp-1.2.0.tar.gz
export-ignore 只对 git archive 生效,不会改变正常检出后的工作目录,也不会自动影响其他打包工具。普通构建或 Docker 构建需要排除测试文件时,仍要配置各自的规则。
.gitignore 也不能替代打包配置。已经被 Git 跟踪的测试文件,即使写进 .gitignore,也不会从版本或发布包中消失。
用标签标记版本,用部署记录区分环境
版本号标明具体版本,环境记录它部署在哪里。同一个版本可以先后部署到 test 和 prod,不必为每个环境维护一套源码。
可以按以下方式记录:
| 对象 | 用途 | 示例 |
|---|---|---|
| commit SHA | 精确定位源码 | CI 记录实际检出的提交 |
| 发布标签 | 标记候选版本或正式版本 | v1.2.0-rc.1、v1.2.0 |
| 部署环境 | 保存环境配置和部署状态 | dev、test、prod |
| 产物标识或摘要 | 确认部署的具体文件或镜像 | 构建编号、镜像 digest |
确认当前提交可以发布后,创建附注标签并推送:
git tag -a v1.2.0 -m "Release 1.2.0"
git push origin refs/tags/v1.2.0
检出这个版本:
git checkout --detach refs/tags/v1.2.0
这会进入 detached HEAD 状态,适合检查或构建该版本。如果需要继续修改,可以从标签创建分支:
git checkout -b hotfix/1.2.1 refs/tags/v1.2.0
同一次发布,建议将测试环境中已经验证的产物部署到生产环境,数据库地址等环境差异通过外部配置提供。这样可以减少重新构建带来的变化。如果项目必须按环境构建不同产物,就应分别记录并验证。
已发布的标签应保持稳定。需要修改时,发布新版本,避免移动旧标签。由于标签可以被删除或强制更新,还需要通过仓库权限或保护规则落实这项约定。
是否需要 dev/test/prod 分支?
仅为排除测试代码,无须创建环境分支。测试应随业务代码一起演进,否则容易出现生产代码已经修改、测试分支却没有同步的情况。
如果需要同时维护多个已发布版本,可以根据维护需求建立 release/1.2 等分支,再为每次发布创建标签。即使采用 dev/test/prod 分支,也仍需单独配置打包规则,分支名称不会决定哪些文件进入产物。
git cherry-pick 可以将指定提交的修改应用到另一条分支,适合有选择地回补修复。但它不会自动处理提交之间的依赖,长期用它拼出不含测试提交的生产版本,容易产生冲突或遗漏。
保留完整源码和测试,通过打包配置控制交付内容,再记录标签与部署产物的对应关系,便于追溯版本。CI 则应持续验证实际要交付的代码。
备注:内容仅供参考。
