上一课你学会了用 Issues 和 PR 协作,用 Branch Protection 守门。但 CI 通过、代码合并之后——怎么告诉世界「这个版本可以用了」?
这节课教你 DevOps 工程师的发布基本功:语义化版本(SemVer)、Git Tag、GitHub Releases、Changelog、以及自动化发布的 Conventional Commits 体系。
SemVer 2.0.0(semver.org)定义了一套版本号的精确规则:
MAJOR.MINOR.PATCH
│ │ └─ 修 bug,行为不变(Bug fix)
│ └─────── 加功能,向后兼容(Feature)
└───────────── 不兼容的 API 变更(Breaking change)
v2.4.1 → Major=2, Minor=4, Patch=1
| 变更类型 | 版本变化 | 例子 |
|---|---|---|
| 修了一个 bug,API 没变 | 1.3.0 → 1.3.1(PATCH) | 修复日志格式错误 |
| 加了一个新功能,老 API 还能用 | 1.3.1 → 1.4.0(MINOR) | 新增 /api/v1/export |
| 改了接口,老调用方会挂 | 1.4.0 → 2.0.0(MAJOR) | 删掉了 /api/v1/old-endpoint |
在 PATCH 后面加 - 和标识符:
1.0.0-alpha.1 # 内部测试
1.0.0-beta.2 # 外部早期测试
1.0.0-rc.1 # Release Candidate,不出意外就是最终版了
v1.0.0,你不能修改它指向的代码。发现 bug?发 v1.0.1。版本号是不可变的标签——这就是为什么 git tag 之后不应该 force push。
Tag 是一个指向特定 commit 的不可变引用(不像 branch 会移动)。两种 tag:
| 类型 | 命令 | 内容 | 用哪个? |
|---|---|---|---|
| Lightweight | git tag v1.0.0 | 只有一个 ref 指针 | ❌ 临时用 |
| Annotated | git tag -a v1.0.0 -m "..." | 含 tagger、日期、message、GPG 签名 | ✅ 永远用这个 |
# 创建一个 annotated tag
git tag -a v1.0.0 -m "Release v1.0.0: initial stable release"
# 查看 tag 详情(annotated 才有这些信息)
git show v1.0.0
# Tagger: bram35mm <...>
# Date: Sat Jul 19 2026
#
# Release v1.0.0: initial stable release
# 推送 tag 到 GitHub
git push origin v1.0.0 # 推送单个 tag
git push origin --tags # 推送所有本地 tag(小心别把旧 tag 也推上去了)
# 删除远程 tag(如果搞错了)
git push origin --delete v1.0.0
git tag -d v1.0.0 # 同时删除本地的
on: push: tags: ['v*']——推一个 v1.0.0 tag,自动触发构建+测试+发布+部署。
GitHub Release 是基于 tag 的发布单元。它 = tag + release notes + 可下载的二进制/assets + 讨论区。
v1.0.0 — Initial Stable Release)# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true # 自动生成 release notes
prerelease: ${{ contains(github.ref, 'rc') || contains(github.ref, 'beta') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SemVer 的数字告诉用户「改了多少」,Changelog 告诉用户「改了什么」。
keepachangelog.com 定义了标准格式:
# Changelog
All notable changes to this project will be documented in this file.
## [1.1.0] - 2026-07-15
### Added
- `POST /api/v1/export` endpoint for data export
- Docker healthcheck in Dockerfile
### Changed
- Upgraded Node.js base image from 22.1 to 22.7
### Deprecated
- `GET /api/v1/legacy` — use `GET /api/v2/data` instead
### Fixed
- Race condition in WebSocket reconnect logic (#142)
### Security
- Patched ReDoS vulnerability in path-to-regexp (#156)
## [1.0.0] - 2026-06-01
### Added
- Initial release with core API
7 个标准分类(只用你需要的):
Added | 新功能 |
Changed | 已有功能的变更 |
Deprecated | 即将移除的功能 |
Removed | 已移除的功能 |
Fixed | Bug 修复 |
Security | 安全漏洞修复 |
Docs | 仅文档变更(非标准,但很多项目用) |
Conventional Commits 是标准化的 commit message 格式。它 = SemVer + 自动化发布之间的桥梁。
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
feat: add user login system # → MINOR bump
fix: resolve navbar bug on mobile # → PATCH bump
feat!: redesign API structure # → MAJOR bump(注意 ! 号)
# 或者用 footer 声明
feat: redesign API structure
BREAKING CHANGE: removed /api/v1/old-endpoint, use /api/v2 instead
| type | 含义 | 版本影响 |
|---|---|---|
feat: | 新功能 | MINOR |
fix: | 修 bug | PATCH |
feat! / 含 BREAKING CHANGE: | 破坏性变更 | MAJOR |
docs: | 仅文档 | 不触发版本 |
chore: | 构建/工具变更 | 不触发版本 |
ci: | CI/CD 配置 | 不触发版本 |
refactor: | 重构 | 不触发版本 |
test: | 测试 | 不触发版本 |
为什么 DevOps 要关心这个?因为当你的团队用 Conventional Commits + semantic-release,每次 push 到 main:
git push → CI 跑 → semantic-release 分析 commit →
自动决定版本号 → 生成 CHANGELOG → git tag → GitHub Release → 部署
零手动操作。这就是 「push on main, ship it」。
目标:在一个测试仓库里走完完整的发布流程。
# 1. 准备一个测试仓库
cd /tmp
mkdir release-demo && cd release-demo && git init
echo "# Release Demo" > README.md
git add . && git commit -m "docs: initial commit"
# 2. 模拟几个 feature 和 fix
echo "export PORT=3000" > .env.example
git add . && git commit -m "feat: add port configuration"
echo 'console.log("server starting")' > index.js
git add . && git commit -m "feat: add entry point"
# 修复一个 bug
echo 'console.log("server starting on port", process.env.PORT)' > index.js
git add . && git commit -m "fix: log port number on startup"
# 3. 用 git log 回顾一下
git log --oneline
# a1b2c3d fix: log port number on startup
# e4f5g6h feat: add entry point
# i7j8k9l feat: add port configuration
# m0n1o2p docs: initial commit
# 4. 创建 annotated tag
git tag -a v1.0.0 -m "Release v1.0.0: first stable release"
# 5. 查看 tag
git show v1.0.0
# 6. 写 CHANGELOG(手动写一次,体会格式)
cat > CHANGELOG.md << 'EOF'
# Changelog
## [1.0.0] - 2026-07-19
### Added
- Port configuration via `.env.example`
- Application entry point with port logging
EOF
git add CHANGELOG.md && git commit -m "docs: add CHANGELOG for v1.0.0"
# 7. 如果这是真实项目,接下来:
# git push origin main
# git push origin v1.0.0
# → GitHub 上会自动触发 Release workflow(如果你配了上面的 Actions)
# → 去 Releases 页面手动创建或等 CI 自动创建
版本发布体系建好了。但一个开源项目不止有代码——最后一课 开源项目维护(0025),你将学习社区治理、许可证选择、GitHub Pages 文档站,以及用 .github 仓库统一管理组织级配置。
on: push: tags: ['v*'] 还是 on: [push]。只有前者在 tag push 时触发。