# Shipping And Launch

> Use when shipping a versioned release with git tag, CHANGELOG, and Release, before pushing tag or publishing Release, when verifying tag, CHANGELOG, and package version consistency, or when planning staged rollout and rollback.

- Skill: `just-silver/shipping-and-launch` (Agent Skill)
- Install (CLI): `npx skillmds@latest add just-silver/shipping-and-launch`
- Raw SKILL.md: https://api.skillmd.com/api/skills/just-silver/shipping-and-launch/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Just-Silver (https://skillmd.com/u/just-silver)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/just-silver/shipping-and-launch

---


# Shipping and Launch（版本发布与回滚）

## Overview

不可重复的发布等于没有发布。每次发布必须可验证（版本单一来源一致）、可追溯（Release body 来自 CHANGELOG 对应小节）、可回退（push 前已知回滚路径）。

## 适用前提：先识别版本单一来源（Single Source of Truth），再谈一致性

本 Skill 的强校验（三处一致）只对**单一版本源仓库**成立（一个 repo 只发布一个版本化产物：单包库 / 单应用）。动手前先识别本仓的版本来源，**不要默认套用三处一致**：

- **单一版本源仓**（单包 / 单应用，如 package.json / *.csproj 与 repo 一一对应）→ 要求 `tag == CHANGELOG == 包版本` 三处一致，可进流水线校验
- **monorepo / 多制品仓**（root + packages/*，或同时产 Docker 镜像 / NuGet / npm / Python 包）→ 各产物版本号可能各不相同，**没有单一"包版本"可对**；识别每个产物的版本来源（各自 package.json / *.csproj / 镜像 tag），tag 语义与本仓约定对齐，**不得为凑三处一致去改各产物版本号**
- **多产物混合发布**（镜像 tag / NuGet / npm 版本来源不同）→ 每个产物各自校验"其 CHANGELOG 小节 ↔ 其版本来源"，而不是用一个 tag 对全仓强制统一

## When to Use

- 打 `v*` tag、发 Release 前
- 检查一次发版是否合规（版本单一来源各处是否一致）
- 定分阶段放量、回滚预案时
- CI 发版链路失败（version consistency / Release body 提取失败）后修复时

**When NOT to use:**

- 日常开发提交（无 tag、无 Release）
- 只改流水线语法不涉及发版
- 纯文档改动无版本变更

## Pre-flight（push tag 前必过）

1. 版本单一来源一致：先按上方「适用前提」识别本仓版本来源（单一版本源仓：`git tag vX.Y.Z` == `CHANGELOG.md` 顶部 `## [X.Y.Z] - YYYY-MM-DD` == 包版本清单；monorepo/多制品仓按各自产物版本源校验，不强行统一）。不一致即停，不打 tag。
2. CHANGELOG 小节存在且非空：Unreleased 已整理为版本小节，按 Keep a Changelog 分组（Added/Changed/Fixed 等），至少列出 breaking changes。空小节不发版。
3. 产物可构建：本地跑本仓构建命令一次通过，产物版本号与 tag 一致。
4. 测试全绿：跑本仓门禁命令全绿后再打 tag。
5. 确认发布面：是否触发下游同步/批量分发、目标是否会被污染，先确认再 push。

## Release Body 规则

- 必须从 `CHANGELOG.md` 该版本小节截段提取，禁止 `git log` 堆砌。
- tag 触发的 checkout 处于 detached HEAD，回推必须显式 `git push origin HEAD:main`（勿裸 push）。

## Rollout 与 Rollback

```
未 push tag → 本地删 tag 重打
已 push tag / 已建 Release → 先删线上 Release，再删远端 tag，再删本地 tag
已同步到下游仓库 → 下游逐个回退到上一版本并重跑旧版安装器
线上严重 bug → 发 patch 版本（如 vX.Y.Z+1），永不复用旧 tag
```

- 平台通用：先删线上 Release 再删远端 tag（`git push --delete origin vX.Y.Z`）。
- 发布附件幂等覆盖：旧版附件从上个 tag 重新构建上传。

## Quick Reference

| 场景 | 动作 |
|------|------|
| 发版前 | 版本单一来源一致 + CHANGELOG 小节 + 构建 + 测试 + 发布面确认 |
| Release body | CHANGELOG 小节截段，禁 `git log` |
| 未 push 想反悔 | `git tag -d vX.Y.Z` |
| 已 push 想反悔 | 删 Release → 删远端 tag → 删本地 tag |
| 线上事故 | 发 patch 版，不复用 tag |

## Common Rationalizations

| Excuse | Reality |
|--------|---------|
| "赶时间，CHANGELOG 回头补" | Release body 就是 CHANGELOG 小节，无小节即发空 Release，CD 直接失败，重发至少 30 分钟 |
| "tag 先打，版本文件随后改" | version consistency 硬校验失败，tag 要删掉重打，更慢 |
| "小版本不用回滚预案" | 无预案即出事时无手段；预案是 push 前 1 分钟确认的三行字，不是文档工程 |
| "Release body 用 git log 拼一下就行" | git log 是噪音不是发布说明；下游只认 CHANGELOG，拼 log 属违规分发 |
| "复用旧 tag 省事" | tag 不可变，复用即污染历史；一律发 patch 版 |
| "monorepo 也要求三处一致" | 先识别版本来源；多产物各有版本，不为凑一致改产物版本号 |

## Red Flags — STOP

- 单一版本源仓 CHANGELOG 顶部版本 ≠ tag 版本 ≠ 包版本
- 未识别版本单一来源就默认套用三处一致（monorepo 强行统一）
- Release body 来自 `git log` 而非 CHANGELOG 小节
- tag 已 push 但无回滚路径（删 Release/删 tag/下游回退任一缺失）
- 批量同步目标未确认即 push tag
- 想复用已发布 tag 号

**以上任一出现 → 停手，回 Pre-flight 修正后再谈发布。**

## Verification

- [ ] 版本单一来源已识别；单一版本源仓 `tag == CHANGELOG == 包版本` 三处一致，有证据（命令输出）
- [ ] CHANGELOG 版本小节存在且非空
- [ ] 本地构建产物版本号与 tag 一致
- [ ] 门禁测试全绿
- [ ] Release body 来源是 CHANGELOG 小节
- [ ] 回滚路径已确认（未 push / 已 push / 已同步三档各有动作）

