Chapter 11Lesson 04~145 minutes

Tags, Releases, Release Notes, Assets, Changelogs, and Release Governance: Diagnostics, Failure Modes, Security, and Performance

Diagnose wrong targets, moved tags, replaced assets, incomplete generated notes, and release/tag deletion mismatches by preserving exact commit and artifact evidence first.

DiagnosticsProvenanceRollbackSupply chain

Learning objectives

  • Use a preserve-evidence-first diagnostic sequence for release incidents.
  • Detect a Release/tag that points at the wrong commit.
  • Explain why moving consumed tags or replacing same-version assets destroys provenance.
  • Diagnose incomplete generated notes from comparison range and metadata.
  • Distinguish Release deletion, tag deletion, asset deletion, and immutable-release behavior.
  • Repair disposable failures with the least destructive correction.
Safety: the intentionally broken examples use fixtures or disposable tags/releases. Never force-update a production tag merely to demonstrate the failure. If a published version is wrong, preserve evidence and prefer a new version/correction path.

1. Diagnostic sequence: preserve identity before trying to fix state

When release consumers report “v1.8.0 is wrong,” first preserve the current mapping. Do not edit notes, replace assets, delete the release, or retag before recording what exists.

# 1) Git ref evidence
git ls-remote --tags origin 'refs/tags/v1.8.0*'
git rev-list -n 1 v1.8.0

# 2) GitHub Release evidence
gh release view v1.8.0 --json tagName,name,isDraft,isPrerelease,isImmutable,targetCommitish,assets,publishedAt,url

# 3) Versioned API evidence including asset digests
gh api -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  repos/{owner}/{repo}/releases/tags/v1.8.0

# 4) Local graph evidence
git log --graph --decorate --oneline --all -20

Only after those identities are recorded should you classify the failure: wrong tag target, wrong Release state, wrong asset bytes, incomplete notes, or deletion misunderstanding.

2. Failure: the Release points to the wrong tag/commit

A common cause is letting release creation implicitly create a missing tag from the current default branch. The Release looks legitimate but its tag names the wrong source state.

Intentionally broken example: operator expected a pre-created v1.8.0 tag but ran gh release create v1.8.0 --notes "release" while the tag was absent. CLI created the tag from the default branch. The original cause is missing release-preparation/tag verification—not a mysterious Release API bug.

Repair: if unpublished/unconsumed and disposable, delete the draft/release and wrongly created tag, then create the correct tag and use --verify-tag. If published/consumed, do not silently retarget the version: publish a corrective version and document the bad version.

3. Failure: a consumed tag is moved

A forced tag update makes the same version name resolve to different commits over time. Clones, caches, deployment records, source archives, and package metadata may disagree forever. A tag ruleset from Chapter 10 can restrict such updates; immutable releases can lock the tag associated with a published Release.

# Safe diagnostic: compare expected recorded SHA with current remote tag target.
EXPECTED=0123456789abcdef0123456789abcdef01234567
CURRENT=$(git ls-remote origin refs/tags/v1.8.0 | awk '{print $1}')
printf 'expected=%s\ncurrent=%s\n' "$EXPECTED" "$CURRENT"

# Do NOT "repair" a consumed production tag with git push --force.
# Publish a corrected version instead.

4. Failure: same release version, rebuilt/replaced asset

If agent-v1.8.0.zip was downloaded yesterday and a new file with the same name replaces it today, the version no longer identifies bytes. That breaks SHA-256 records and makes incident investigation unreliable. The CLI gh release upload --clobber is intentionally dangerous because it deletes the existing asset before uploading the replacement; if upload then fails, the original is lost.

Production rule: build once, hash once, publish once. If bytes change, version changes. Immutable releases can technically enforce asset immutability after publication.

5. Failure: generated notes omit important changes

Generated notes depend on the comparison range and PR metadata. Missing labels, excluded authors/labels, wrong previous tag, or changes that never arrived through merged PRs can change output. Diagnose the inputs before rewriting the notes manually.

# Inspect labels on merged PRs in the intended range (example search).
gh pr list --state merged --base main --json number,title,labels,mergedAt

# Inspect release-note config from the default branch.
gh api repos/{owner}/{repo}/contents/.github/release.yml \
  -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10"

# When generating a new disposable release, pin the intended comparison start.
gh release create v1.8.1 --verify-tag --generate-notes --notes-start-tag v1.8.0

The goal is not to make every PR appear; it is to make the inclusion/exclusion policy deliberate and auditable.

6. Failure: deleting a Release while assuming the tag disappears—or vice versa

Operation Release object Git tag Assets
gh release delete TAG Deleted Normally remains Deleted with Release
gh release delete TAG --cleanup-tag Deleted Also deleted Deleted
Delete Git tag ref Release may remain but its relationship is broken/altered Deleted Release assets remain until Release is deleted
Delete one asset Release remains Unchanged Only selected asset removed

With immutable releases, asset/tag deletion is restricted after publication. Deleting the immutable Release changes what can be done with the associated tag, but GitHub also prevents reuse of the same immutable-release tag name.

7. Authentication succeeds but release mutation fails

Separate login from authorization. A token can authenticate and still lack Contents: write or repository write access. The Releases REST endpoint also has a special workflow-file boundary: if the target commit changes .github/workflows/ relative to the default branch, the credential may require workflow-write permission, and GITHUB_TOKEN cannot be elevated for this specific API requirement.

Do not respond to a 403/404 by broadening a token blindly. Inspect the endpoint, target commit, repository role, and documented permission set first.

8. Least-destructive recovery patterns

Failure Preferred recovery
Wrong draft tag, no consumers Delete draft/release + wrong disposable tag; recreate exact tag
Wrong published version, consumers exist Publish corrected version; mark bad version clearly; preserve incident evidence
Bad asset bytes New version/build; do not replace same-version asset
Incomplete notes Correct metadata/config and notes; do not move tag to “fix” prose
Latest points to undesired stable Adjust latest designation/publish fixed stable release; do not redefine old tag

9. Lesson summary

Release diagnosis begins with exact identities: tag SHA, Release fields, asset digests, and graph. Wrong targets, moved tags, replaced assets, and deletion assumptions are different failures requiring different corrections. Least-destructive recovery preserves consumed version meaning and produces a new auditable version when necessary.

Knowledge check

A Release is wrong because its tag points to the wrong commit and users already downloaded it. What should you avoid?

Why is gh release upload --clobber risky?

Generated notes missed a security-relevant PR. What should you inspect first?

Does deleting a GitHub Release normally delete its Git tag?

An API call returns 403 even though gh auth status is healthy. What category of problem is this?

Next lesson

Next: Checkpoint Lab — Tags, Releases, Release Notes, Assets, Changelogs, and Release Governance

Further reading — current official GitHub sources

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.