semantic-versioning
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSemantic Versioning
语义化版本控制(Semantic Versioning)
Automate version management and changelog generation following SemVer principles.
遵循SemVer原则,实现版本管理与变更日志生成的自动化。
When to Use This Skill
适用场景
Use this skill when:
- Implementing version numbering standards
- Automating release versioning
- Generating changelogs automatically
- Setting up release pipelines
- Managing package versions
适用于以下场景:
- 实施版本编号标准
- 自动化发布版本控制
- 自动生成变更日志
- 搭建发布流水线
- 管理包版本
Prerequisites
前置条件
- Git repository with commit history
- Node.js (for most tools)
- Conventional commits (recommended)
- 带有提交历史的Git仓库
- Node.js(适用于大多数工具)
- 规范化提交(Conventional commits,推荐使用)
Semantic Versioning Basics
语义化版本控制基础
Version Format
版本格式
MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]
Examples:
1.0.0
2.1.3
1.0.0-alpha.1
1.0.0-beta.2+build.123MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]
Examples:
1.0.0
2.1.3
1.0.0-alpha.1
1.0.0-beta.2+build.123Version Components
版本组成部分
| Component | When to Increment |
|---|---|
| MAJOR | Breaking changes (incompatible API changes) |
| MINOR | New features (backward compatible) |
| PATCH | Bug fixes (backward compatible) |
| PRERELEASE | Pre-release versions (alpha, beta, rc) |
| BUILD | Build metadata (ignored in precedence) |
| 组成部分 | 升级时机 |
|---|---|
| MAJOR | 破坏性变更(不兼容的API变更) |
| MINOR | 新增功能(向后兼容) |
| PATCH | Bug修复(向后兼容) |
| PRERELEASE | 预发布版本(alpha、beta、rc) |
| BUILD | 构建元数据(版本优先级中忽略) |
Version Precedence
版本优先级
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta
< 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11
< 1.0.0-rc.1 < 1.0.0 < 2.0.01.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta
< 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11
< 1.0.0-rc.1 < 1.0.0 < 2.0.0Conventional Commits to Version
规范化提交与版本映射
yaml
Commit Type → Version Bump:
feat: → MINOR
fix: → PATCH
docs: → PATCH (or no release)
style: → PATCH (or no release)
refactor: → PATCH
perf: → PATCH
test: → No release
chore: → No release
BREAKING CHANGE: → MAJOR
feat!: → MAJOR
fix!: → MAJORyaml
Commit Type → Version Bump:
feat: → MINOR
fix: → PATCH
docs: → PATCH (or no release)
style: → PATCH (or no release)
refactor: → PATCH
perf: → PATCH
test: → No release
chore: → No release
BREAKING CHANGE: → MAJOR
feat!: → MAJOR
fix!: → MAJORsemantic-release
semantic-release
Installation
安装
bash
npm install --save-dev semantic-release \
@semantic-release/changelog \
@semantic-release/gitbash
npm install --save-dev semantic-release \
@semantic-release/changelog \
@semantic-release/gitConfiguration
配置
json
// .releaserc.json
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/changelog", {
"changelogFile": "CHANGELOG.md"
}],
["@semantic-release/npm", {
"npmPublish": true
}],
["@semantic-release/git", {
"assets": ["CHANGELOG.md", "package.json", "package-lock.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}],
"@semantic-release/github"
]
}json
// .releaserc.json
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/changelog", {
"changelogFile": "CHANGELOG.md"
}],
["@semantic-release/npm", {
"npmPublish": true
}],
["@semantic-release/git", {
"assets": ["CHANGELOG.md", "package.json", "package-lock.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}],
"@semantic-release/github"
]
}Advanced Configuration
高级配置
javascript
// release.config.js
module.exports = {
branches: [
'main',
{ name: 'beta', prerelease: true },
{ name: 'alpha', prerelease: true }
],
plugins: [
['@semantic-release/commit-analyzer', {
preset: 'angular',
releaseRules: [
{ type: 'docs', release: 'patch' },
{ type: 'refactor', release: 'patch' },
{ type: 'style', release: 'patch' },
{ type: 'perf', release: 'patch' },
{ breaking: true, release: 'major' }
]
}],
['@semantic-release/release-notes-generator', {
preset: 'angular',
writerOpts: {
commitsSort: ['subject', 'scope']
}
}],
'@semantic-release/changelog',
'@semantic-release/npm',
'@semantic-release/git',
'@semantic-release/github'
]
};javascript
// release.config.js
module.exports = {
branches: [
'main',
{ name: 'beta', prerelease: true },
{ name: 'alpha', prerelease: true }
],
plugins: [
['@semantic-release/commit-analyzer', {
preset: 'angular',
releaseRules: [
{ type: 'docs', release: 'patch' },
{ type: 'refactor', release: 'patch' },
{ type: 'style', release: 'patch' },
{ type: 'perf', release: 'patch' },
{ breaking: true, release: 'major' }
]
}],
['@semantic-release/release-notes-generator', {
preset: 'angular',
writerOpts: {
commitsSort: ['subject', 'scope']
}
}],
'@semantic-release/changelog',
'@semantic-release/npm',
'@semantic-release/git',
'@semantic-release/github'
]
};GitHub Actions Integration
GitHub Actions 集成
yaml
undefinedyaml
undefined.github/workflows/release.yml
.github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-releaseundefinedname: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-releaseundefinedstandard-version
standard-version
Installation
安装
bash
npm install --save-dev standard-versionbash
npm install --save-dev standard-versionConfiguration
配置
json
// .versionrc.json
{
"types": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "docs", "section": "Documentation" },
{ "type": "style", "section": "Styling" },
{ "type": "refactor", "section": "Code Refactoring" },
{ "type": "perf", "section": "Performance" },
{ "type": "test", "section": "Tests" },
{ "type": "chore", "section": "Maintenance" }
],
"skip": {
"bump": false,
"changelog": false,
"commit": false,
"tag": false
},
"commitUrlFormat": "https://github.com/owner/repo/commit/{{hash}}",
"compareUrlFormat": "https://github.com/owner/repo/compare/{{previousTag}}...{{currentTag}}"
}json
// .versionrc.json
{
"types": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "docs", "section": "Documentation" },
{ "type": "style", "section": "Styling" },
{ "type": "refactor", "section": "Code Refactoring" },
{ "type": "perf", "section": "Performance" },
{ "type": "test", "section": "Tests" },
{ "type": "chore", "section": "Maintenance" }
],
"skip": {
"bump": false,
"changelog": false,
"commit": false,
"tag": false
},
"commitUrlFormat": "https://github.com/owner/repo/commit/{{hash}}",
"compareUrlFormat": "https://github.com/owner/repo/compare/{{previousTag}}...{{currentTag}}"
}Usage
使用方法
bash
undefinedbash
undefinedFirst release
首次发布
npx standard-version --first-release
npx standard-version --first-release
Regular release (auto-detect version bump)
常规发布(自动检测版本升级)
npx standard-version
npx standard-version
Specific version bump
指定版本升级类型
npx standard-version --release-as minor
npx standard-version --release-as 1.1.0
npx standard-version --release-as minor
npx standard-version --release-as 1.1.0
Pre-release
预发布版本
npx standard-version --prerelease alpha
npx standard-version --prerelease beta
npx standard-version --prerelease alpha
npx standard-version --prerelease beta
Dry run
试运行
npx standard-version --dry-run
npx standard-version --dry-run
Skip specific steps
跳过指定步骤
npx standard-version --skip.changelog
undefinednpx standard-version --skip.changelog
undefinedNPM Scripts
NPM 脚本
json
// package.json
{
"scripts": {
"release": "standard-version",
"release:minor": "standard-version --release-as minor",
"release:major": "standard-version --release-as major",
"release:alpha": "standard-version --prerelease alpha",
"release:beta": "standard-version --prerelease beta",
"release:dry": "standard-version --dry-run"
}
}json
// package.json
{
"scripts": {
"release": "standard-version",
"release:minor": "standard-version --release-as minor",
"release:major": "standard-version --release-as major",
"release:alpha": "standard-version --prerelease alpha",
"release:beta": "standard-version --prerelease beta",
"release:dry": "standard-version --dry-run"
}
}Changelog Generation
变更日志生成
conventional-changelog
conventional-changelog
bash
undefinedbash
undefinedInstall
安装
npm install -g conventional-changelog-cli
npm install -g conventional-changelog-cli
Generate changelog
生成变更日志
conventional-changelog -p angular -i CHANGELOG.md -s
conventional-changelog -p angular -i CHANGELOG.md -s
Generate all history
生成全部历史日志
conventional-changelog -p angular -i CHANGELOG.md -s -r 0
undefinedconventional-changelog -p angular -i CHANGELOG.md -s -r 0
undefinedgit-cliff
git-cliff
bash
undefinedbash
undefinedInstall
安装
cargo install git-cliff
cargo install git-cliff
Generate changelog
生成变更日志
git cliff -o CHANGELOG.md
```tomlgit cliff -o CHANGELOG.md
```tomlcliff.toml
cliff.toml
[changelog]
header = "# Changelog\n\n"
body = """
{% for group, commits in commits | group_by(attribute="group") %}
[changelog]
header = "# Changelog\n\n"
body = """
{% for group, commits in commits | group_by(attribute="group") %}
{{ group | upper_first }}
{{ group | upper_first }}
{% for commit in commits %}
- {{ commit.message | upper_first }}
{% endfor %} {% endfor %} """ trim = true
[git]
conventional_commits = true
filter_unconventional = true
commit_preprocessors = [
{ pattern = '((\w+)\s#([0-9]+))', replace = "(#${2})" },
]
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^doc", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactoring" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore", group = "Miscellaneous" },
]
filter_commits = true
tag_pattern = "v[0-9]*"
undefined{% for commit in commits %}
- {{ commit.message | upper_first }}
{% endfor %} {% endfor %} """ trim = true
[git]
conventional_commits = true
filter_unconventional = true
commit_preprocessors = [
{ pattern = '((\w+)\s#([0-9]+))', replace = "(#${2})" },
]
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^doc", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactoring" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore", group = "Miscellaneous" },
]
filter_commits = true
tag_pattern = "v[0-9]*"
undefinedVersion Bumping Scripts
版本号升级脚本
Bash Script
Bash 脚本
bash
#!/bin/bashbash
#!/bin/bashbump-version.sh
bump-version.sh
CURRENT_VERSION=$(cat package.json | jq -r '.version')
echo "Current version: $CURRENT_VERSION"
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
case $1 in
major)
NEW_VERSION="$((MAJOR + 1)).0.0"
;;
minor)
NEW_VERSION="$MAJOR.$((MINOR + 1)).0"
;;
patch)
NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))"
;;
*)
echo "Usage: $0 {major|minor|patch}"
exit 1
;;
esac
echo "New version: $NEW_VERSION"
CURRENT_VERSION=$(cat package.json | jq -r '.version')
echo "Current version: $CURRENT_VERSION"
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
case $1 in
major)
NEW_VERSION="$((MAJOR + 1)).0.0"
;;
minor)
NEW_VERSION="$MAJOR.$((MINOR + 1)).0"
;;
patch)
NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))"
;;
*)
echo "Usage: $0 {major|minor|patch}"
exit 1
;;
esac
echo "New version: $NEW_VERSION"
Update package.json
Update package.json
npm version $NEW_VERSION --no-git-tag-version
npm version $NEW_VERSION --no-git-tag-version
Create git tag
Create git tag
git add package.json package-lock.json
git commit -m "chore: bump version to $NEW_VERSION"
git tag -a "v$NEW_VERSION" -m "Version $NEW_VERSION"
undefinedgit add package.json package-lock.json
git commit -m "chore: bump version to $NEW_VERSION"
git tag -a "v$NEW_VERSION" -m "Version $NEW_VERSION"
undefinedPython Script
Python 脚本
python
#!/usr/bin/env python3python
#!/usr/bin/env python3bump_version.py
bump_version.py
import re
import sys
import subprocess
def get_current_version():
with open('setup.py', 'r') as f:
content = f.read()
match = re.search(r"version='"['"]", content)
return match.group(1) if match else None
def bump_version(current, bump_type):
major, minor, patch = map(int, current.split('.'))
if bump_type == 'major':
return f'{major + 1}.0.0'
elif bump_type == 'minor':
return f'{major}.{minor + 1}.0'
elif bump_type == 'patch':
return f'{major}.{minor}.{patch + 1}'
else:
raise ValueError(f'Invalid bump type: {bump_type}')def update_version(old_version, new_version):
with open('setup.py', 'r') as f:
content = f.read()
content = content.replace(f"version='{old_version}'", f"version='{new_version}'")
with open('setup.py', 'w') as f:
f.write(content)if name == 'main':
bump_type = sys.argv[1] if len(sys.argv) > 1 else 'patch'
current = get_current_version()
new = bump_version(current, bump_type)
print(f'Bumping version: {current} → {new}')
update_version(current, new)
subprocess.run(['git', 'add', 'setup.py'])
subprocess.run(['git', 'commit', '-m', f'chore: bump version to {new}'])
subprocess.run(['git', 'tag', '-a', f'v{new}', '-m', f'Version {new}'])undefinedimport re
import sys
import subprocess
def get_current_version():
with open('setup.py', 'r') as f:
content = f.read()
match = re.search(r"version='"['"]", content)
return match.group(1) if match else None
def bump_version(current, bump_type):
major, minor, patch = map(int, current.split('.'))
if bump_type == 'major':
return f'{major + 1}.0.0'
elif bump_type == 'minor':
return f'{major}.{minor + 1}.0'
elif bump_type == 'patch':
return f'{major}.{minor}.{patch + 1}'
else:
raise ValueError(f'Invalid bump type: {bump_type}')def update_version(old_version, new_version):
with open('setup.py', 'r') as f:
content = f.read()
content = content.replace(f"version='{old_version}'", f"version='{new_version}'")
with open('setup.py', 'w') as f:
f.write(content)if name == 'main':
bump_type = sys.argv[1] if len(sys.argv) > 1 else 'patch'
current = get_current_version()
new = bump_version(current, bump_type)
print(f'Bumping version: {current} → {new}')
update_version(current, new)
subprocess.run(['git', 'add', 'setup.py'])
subprocess.run(['git', 'commit', '-m', f'chore: bump version to {new}'])
subprocess.run(['git', 'tag', '-a', f'v{new}', '-m', f'Version {new}'])undefinedMulti-Package Versioning
多包版本管理
Lerna
Lerna
json
// lerna.json
{
"version": "independent",
"npmClient": "npm",
"command": {
"version": {
"conventionalCommits": true,
"message": "chore(release): publish"
},
"publish": {
"conventionalCommits": true
}
}
}bash
undefinedjson
// lerna.json
{
"version": "independent",
"npmClient": "npm",
"command": {
"version": {
"conventionalCommits": true,
"message": "chore(release): publish"
},
"publish": {
"conventionalCommits": true
}
}
}bash
undefinedVersion all changed packages
为所有变更包升级版本
npx lerna version
npx lerna version
Publish all changed packages
发布所有变更包
npx lerna publish
undefinednpx lerna publish
undefinedChangesets
Changesets
bash
undefinedbash
undefinedInitialize
初始化
npx @changesets/cli init
npx @changesets/cli init
Add changeset
添加变更记录
npx changeset add
npx changeset add
Version packages
升级包版本
npx changeset version
npx changeset version
Publish
发布包
npx changeset publish
undefinednpx changeset publish
undefinedCommon Issues
常见问题
Issue: No Version Bump
问题:未触发版本升级
Problem: semantic-release not creating release
Solution: Check commit format, verify branch configuration
问题描述:semantic-release未创建发布版本
解决方法:检查提交格式,验证分支配置
Issue: Wrong Version Calculated
问题:版本计算错误
Problem: Major/minor/patch incorrectly determined
Solution: Review commit analyzer rules, check for missing prefixes
问题描述:MAJOR/MINOR/PATCH版本号判断错误
解决方法:检查提交分析规则,确认是否缺少前缀
Issue: Duplicate Tags
问题:标签重复
Problem: Tag already exists
Solution: Clean up tags, verify version wasn't already released
问题描述:标签已存在
解决方法:清理重复标签,确认版本未被发布过
Best Practices
最佳实践
- Use conventional commits consistently
- Automate version bumping in CI
- Generate changelogs automatically
- Tag releases in Git
- Use pre-release versions for testing
- Document breaking changes clearly
- Include migration guides for major versions
- Lock dependencies with exact versions
- 持续使用规范化提交
- 在CI中自动化版本号升级
- 自动生成变更日志
- 在Git中标记发布版本
- 使用预发布版本进行测试
- 清晰记录破坏性变更
- 为大版本提供迁移指南
- 使用精确版本锁定依赖
Related Skills
相关技能
- git-workflow - Branching strategies
- github-actions - CI automation
- feature-flags - Progressive rollout
- git-workflow - 分支策略
- github-actions - CI自动化
- feature-flags - 渐进式发布