用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/rudironsoni/Ghost --skill dotnet-release-management命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | dotnet-release-management |
| description | Manages .NET release lifecycle. NBGV versioning, SemVer, changelogs, pre-release, branching. |
| allowed-tools | ["Read","Grep","Glob","Bash","Write","Edit"] |
Release lifecycle management for .NET projects: Nerdbank.GitVersioning (NBGV) setup with version.json configuration, version height calculation, and public release vs pre-release modes; SemVer 2.0 strategy for .NET libraries (when to bump major/minor/patch, API compatibility considerations) and applications (build metadata, deployment versioning); changelog generation (Keep a Changelog format, auto-generation with git-cliff and conventional commits); pre-release version workflows (alpha, beta, rc, stable progression); and release branching patterns (release branches, hotfix branches, trunk-based releases with tags).
Version assumptions: .NET 8.0+ baseline. Nerdbank.GitVersioning 3.6+ (current stable). SemVer 2.0 specification.
Cross-references: [skill:dotnet-gha-publish] for CI publish workflows, [skill:dotnet-ado-publish] for ADO publish workflows, [skill:dotnet-nuget-authoring] for NuGet package versioning properties.
NBGV calculates deterministic version numbers from git history. The version is derived from a version.json file and the git commit height (number of commits since the version was set), producing unique versions for every commit without manual version bumps.
# Install NBGV CLI tool
dotnet tool install --global nbgv
# Initialize NBGV in a repository
nbgv install
# This creates version.json at the repo root
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
"version": "1.0",
"publicReleaseRefSpec": [
"^refs/heads/main$",
"^refs/tags/v\\d+\\.\\d+(\\.\\d+)?(-.*)?$"
],
"cloudBuild": {
"buildNumber": {
"enabled": true
},
"setVersionVariables": true
}
}
| Field | Purpose | Example |
|---|---|---|
version | Base version (major.minor, optional patch) | "1.0", "2.3.0" |
publicReleaseRefSpec | Regex patterns for branches/tags that produce public versions | ["^refs/heads/main$"] |
cloudBuild.buildNumber.enabled | Set CI build number to calculated version | true |
cloudBuild.setVersionVariables | Export version as CI environment variables | true |
nugetPackageVersion | Override NuGet package version format | {"semVer": 2} |
assemblyVersion.precision | Assembly version component count | "major", "minor", "build", "revision" |
inherit | Inherit from parent directory version.json | true |
NBGV counts the number of commits since the version field was last changed in version.json. This count becomes the patch version:
version.json: "version": "1.2"
Commit history:
abc1234 feat: add caching -> 1.2.3
def5678 fix: null check -> 1.2.2
ghi9012 chore: update deps -> 1.2.1
jkl3456 Bump version to 1.2 -> 1.2.0 (version.json changed here)
The version height ensures every commit has a unique version without manual intervention.
{
"version": "1.2-beta",
"publicReleaseRefSpec": [
"^refs/heads/main$",
"^refs/tags/v\\d+\\.\\d+(\\.\\d+)?(-.*)?$"
]
}
| Branch/Ref | Computed Version | Notes |
|---|---|---|
main (public) | 1.2.5-beta | Public pre-release, height=5 |
feature/foo (non-public) | 1.2.5-beta.gcommithash | Includes git hash suffix |
Tag v1.2.5 (public) | 1.2.5 | Remove -beta before tagging |
To release a stable version, remove the pre-release suffix from version.json before the release commit:
{
"version": "1.2"
}
# Show the current calculated version
nbgv get-version
# Show specific version properties
nbgv get-version -v NuGetPackageVersion
nbgv get-version -v SemVer2
# Prepare for a release (creates release branch, bumps version)
nbgv prepare-release
# Set version variables for CI
nbgv cloud
For monorepos with independently versioned projects, place version.json in each project directory and use inherit:
repo-root/
version.json <- { "version": "1.0" }
src/
LibraryA/
version.json <- { "version": "2.3", "inherit": true }
LibraryB/
version.json <- { "version": "1.1-beta", "inherit": true }
The inherit field pulls settings (like publicReleaseRefSpec and cloudBuild) from the parent version.json while overriding the version number.
SemVer 2.0 specifies version format MAJOR.MINOR.PATCH:
| Change Type | Version Bump | Examples |
|---|---|---|
| Breaking API changes | Major | Removing public types/members, changing method signatures, renaming namespaces |
| New features (backward compatible) | Minor | Adding public types/members, new extension methods, new overloads |
| Bug fixes (backward compatible) | Patch | Fixing incorrect behavior, performance improvements, internal refactors |
| Change | Breaking? | Notes |
|---|---|---|
| Remove public type | Yes (Major) | Consumers referencing it will fail to compile |
| Remove public method | Yes (Major) | Direct callers will fail |
| Add required parameter to public method | Yes (Major) | Existing callers do not supply it |
| Add optional parameter to public method | No (Minor) | Binary compatible but source-breaking for callers using named arguments |
| Change return type | Yes (Major) | Binary and source breaking |
| Add new public type | No (Minor) | No existing code affected |
| Add new overload | No (Minor) | Existing calls still resolve |
| Change internal implementation | No (Patch) | No public API change |
| Change default value of optional parameter | No (Patch) | Binary compatible (value embedded at call site on recompile) |
| Seal a previously unsealed class | Yes (Major) | Consumers inheriting from it will fail |
| Make a virtual method non-virtual | Yes (Major) | Consumers overriding it will fail |
Use EnablePackageValidation to catch accidental breaking changes. For full package validation setup, see [skill:dotnet-nuget-authoring].
<PropertyGroup>
<EnablePackageValidation>true</EnablePackageValidation>
<PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion>
</PropertyGroup>
Applications (web apps, desktop apps, services) have different versioning considerations than libraries because they do not have public API consumers.
| Approach | Format | Best For |
|---|---|---|
| SemVer (feature-driven) | 1.2.3 | Installed desktop/mobile apps with user-visible versioning |
| CalVer (calendar-based) | 2024.1.15 | SaaS apps with continuous deployment |
| Build number | 1.2.3+42 | CI-driven versioning with build metadata |
| NBGV height | 1.2.42 | Automated versioning from git commits |
SemVer 2.0 allows + suffixed build metadata that does not affect version precedence:
1.2.3+build.42 Build number
1.2.3+abcdef Git commit hash
1.2.3+2024.01.15 Build date
1.2.3-beta.1+42 Pre-release with build metadata
Build metadata is useful for tracing a deployed binary back to its source commit. NBGV appends git metadata automatically.
For continuously deployed services, version stamping aids troubleshooting:
<PropertyGroup>
<!-- Embed full version in assembly for runtime introspection -->
<InformationalVersion>1.2.3+abcdef.2024-01-15</InformationalVersion>
</PropertyGroup>
Read at runtime:
var version = typeof(Program).Assembly
.GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>()
?.InformationalVersion;
// Returns "1.2.3+abcdef.2024-01-15"
The Keep a Changelog format is a widely adopted standard:
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Widget caching support for improved throughput
## [1.2.0] - 2024-03-15
### Added
- Fluent API for widget configuration
- Batch processing support
### Changed
- Improved error messages for invalid widget states
### Fixed
- Memory leak in widget pool under high concurrency
- Timezone handling in scheduled widget operations
### Deprecated
- `Widget.Create()` static method -- use `WidgetBuilder` instead
## [1.1.0] - 2024-01-10
### Added
- Widget serialization support
[Unreleased]: https://github.com/mycompany/widgets/compare/v1.2.0...HEAD
[1.2.0]: https://github.com/mycompany/widgets/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/mycompany/widgets/releases/tag/v1.1.0
| Section | Purpose |
|---|---|
Added | New features |
Changed | Changes to existing functionality |
Deprecated | Features that will be removed in future versions |
Removed | Features removed in this release |
Fixed | Bug fixes |
Security | Vulnerability fixes |
git-cliff generates changelogs from conventional commits:
# Install git-cliff
cargo install git-cliff
# Generate changelog for all versions
git cliff --output CHANGELOG.md
# Generate changelog for unreleased changes only
git cliff --unreleased --output CHANGELOG.md
# Generate notes for a specific tag range
git cliff --tag v1.2.0 --unreleased
Configure cliff.toml for .NET conventional commit patterns:
# cliff.toml
[changelog]
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [Unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}\n
"""
trim = true
[git]
conventional_commits = true
filter_unconventional = true
commit_parsers = [
{ message = "^feat", group = "Added" },
{ message = "^fix", group = "Fixed" },
{ message = "^perf", group = "Changed" },
{ message = "^refactor", group = "Changed" },
{ message = "^docs", group = "Documentation" },
{ message = "^chore\\(deps\\)", group = "Dependencies" },
{ message = "^chore", skip = true },
{ message = "^ci", skip = true },
{ message = "^test", skip = true },
]
feat: add widget caching support
fix: correct timezone handling in scheduler
feat!: rename Widget.Create() to WidgetBuilder.Build()
chore(deps): update System.Text.Json to 8.0.5
docs: update API reference for caching
Breaking change in body:
feat: redesign widget API
BREAKING CHANGE: Widget.Create() has been removed. Use WidgetBuilder instead.
| Prefix | SemVer Impact | Changelog Section |
|---|---|---|
feat: | Minor | Added |
fix: | Patch | Fixed |
feat!: or BREAKING CHANGE: | Major | Breaking Changes |
perf: | Patch | Changed |
refactor: | Patch | Changed |
docs: | None | Documentation |
chore: | None | (skipped) |
alpha -> beta -> rc -> stable
1.0.0-alpha.1 Early development, API unstable
1.0.0-alpha.2 Continued alpha iteration
1.0.0-beta.1 Feature-complete, API stabilizing
1.0.0-beta.2 Beta bug fixes
1.0.0-rc.1 Release candidate, final validation
1.0.0-rc.2 RC bug fix (if needed)
1.0.0 Stable release
# Start with pre-release suffix in version.json
# version.json: { "version": "1.0-alpha" }
# Produces: 1.0.1-alpha, 1.0.2-alpha, ...
# Promote to beta
# Edit version.json: { "version": "1.0-beta" }
# Produces: 1.0.1-beta, 1.0.2-beta, ...
# Promote to rc
# Edit version.json: { "version": "1.0-rc" }
# Produces: 1.0.1-rc, 1.0.2-rc, ...
# Promote to stable
# Edit version.json: { "version": "1.0" }
# Produces: 1.0.1, 1.0.2, ...
For projects not using NBGV:
<!-- In .csproj or Directory.Build.props -->
<PropertyGroup>
<VersionPrefix>1.0.0</VersionPrefix>
<VersionSuffix>beta.1</VersionSuffix>
<!-- Produces: 1.0.0-beta.1 -->
</PropertyGroup>
Override from CI:
# CI sets the pre-release suffix
dotnet pack /p:VersionSuffix="beta.$(BUILD_NUMBER)"
# Stable release: omit VersionSuffix
dotnet pack
NuGet follows SemVer 2.0 pre-release precedence:
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.2
1.0.0-alpha.2 < 1.0.0-beta
1.0.0-beta < 1.0.0-beta.1
1.0.0-rc.1 < 1.0.0
Numeric identifiers are compared as integers; alphabetic identifiers are compared lexically.
The simplest release model. All development happens on main, releases are marked with tags.
main: A -- B -- C -- D -- E -- F -- G
| |
v1.0.0 v1.1.0
# Tag and push for release
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
Best for: Libraries, small teams, continuous delivery.
Create a release branch for stabilization while main continues development.
main: A -- B -- C -- D -- E -- F -- G
\
release/1.0: C' -- D' -- E'
|
v1.0.0
# Create release branch
git checkout -b release/1.0 main
# Stabilize on release branch (bug fixes only)
git commit -m "fix: correct null check in widget pool"
# Tag and release
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin release/1.0 v1.0.0
# Merge fixes back to main
git checkout main
git merge release/1.0
Best for: Products with support contracts, LTS versions, teams needing parallel development and stabilization.
NBGV automates release branch creation and version bumping:
# Creates release/v1.0 branch, bumps main to 1.1-alpha
nbgv prepare-release
# What this does:
# 1. Creates branch "release/v1.0" from current commit
# 2. On release branch: removes pre-release suffix (version: "1.0")
# 3. On main: bumps to "1.1-alpha" (next development version)
Emergency fixes for released versions:
main: A -- B -- C -- D -- E
\
release/1.0: C' -- v1.0.0
\
hotfix/1.0.1: F' -- v1.0.1
# Branch from the release tag
git checkout -b hotfix/1.0.1 v1.0.0
# Fix the critical issue
git commit -m "fix: critical security vulnerability in auth handler"
# Tag and release the hotfix
git tag -a v1.0.1 -m "Hotfix v1.0.1"
git push origin hotfix/1.0.1 v1.0.1
# Merge hotfix back to main
git checkout main
git merge hotfix/1.0.1
| Pattern | Release Cadence | Parallel Versions | Complexity |
|---|---|---|---|
| Trunk + tags | Continuous | No | Low |
| Release branches | Scheduled | Yes | Medium |
| GitFlow (full) | Scheduled | Yes | High |
For most .NET open-source libraries, trunk-based with tags and NBGV is sufficient. Reserve release branches for products that maintain multiple supported versions simultaneously.
NBGV version.json uses major.minor only (not major.minor.patch) -- the patch version is calculated from commit height. Setting "version": "1.2.3" fixes the patch to 3, defeating the purpose of automatic versioning.
NBGV requires git history to calculate version height -- shallow clones (git clone --depth 1) produce incorrect versions. In CI, use fetch-depth: 0 with actions/checkout to get full history.
publicReleaseRefSpec patterns are regex, not globs -- use ^refs/heads/main$ not main. Missing anchors will match unintended refs.
SemVer pre-release ordering is lexical for non-numeric segments -- alpha < beta < rc because of alphabetical comparison. Numeric segments are compared as integers, so beta.2 < beta.10 (because 2 < 10). Do not assume lexical ordering for numeric identifiers.
Do not use CalVer for NuGet libraries -- NuGet resolution depends on SemVer ordering. CalVer versions like 2024.1.0 work mechanically but violate consumer expectations for API stability signals.
VersionPrefix + VersionSuffix combine to form Version -- setting all three causes conflicts. Use either Version alone or VersionPrefix/VersionSuffix together, not both.
Keep a Changelog [Unreleased] section must be updated before release -- move entries from [Unreleased] to the new version section, update comparison links, and add a new empty [Unreleased] section.
nbgv prepare-release modifies both the new branch and the current branch -- it bumps the version on the current branch to the next minor. Run it from the branch you want to continue development on (usually main).