Tags, Releases, Release Notes, Assets, Changelogs, and Release Governance: Concepts, Architecture, and Mental Model
Separate Git refs from GitHub Release objects, then connect version identity, notes, assets, provenance, support lines, and rollback expectations into one release-governance model.
Learning objectives
- Distinguish a Git tag/ref from a GitHub Release database object and release page.
- Explain draft, prerelease, latest, tag target, release-branch, and support-line relationships without treating them as Git primitives.
- Separate generated source archives from manually uploaded release assets and identify which evidence belongs to each.
- Explain generated/manual release notes, comparison ranges, changelog categories, and why labels influence generated notes.
- Distinguish social immutability from GitHub immutable-release enforcement and understand the associated release attestation.
- Inspect tags and releases read-only before creating or changing them.
1. The practical problem: a version name is not enough
A deployment pipeline, a user downloading a binary, and an operator deciding whether to roll back all need the same answer: what exact source state and artifact does this version name identify? Git gives you refs and objects; GitHub adds a release object, notes, downloadable assets, visibility, and governance around a tag. Confusing those layers creates releases whose labels look authoritative while their commit or artifact identity is ambiguous.
Chapter 10 treated protected refs as change-control boundaries. Chapter 11 applies the same evidence-first thinking to the point where a tested commit becomes a named software version consumed by other people or systems.
2. Three identities must agree: commit, tag, and Release
A Git tag is a Git ref under
refs/tags/.... An annotated tag also has a tag object
containing a message, tagger metadata, and optionally a
cryptographic signature. A GitHub Release is hosted
metadata associated with a tag: a title, body,
draft/prerelease/latest state, timestamps, uploaded assets, links,
and API identity. A release is therefore based on a tag, but it is
not the tag itself.
| Layer | Example | Source of truth |
|---|---|---|
| Commit | 8f3… |
Exact source tree/history identity |
| Git tag | refs/tags/v1.4.0 |
Named Git reference; annotated tags can carry message/signature |
| GitHub Release | Release ID + tag_name=v1.4.0 |
Hosted distribution metadata and assets |
| Uploaded asset | app-v1.4.0.zip + SHA-256 |
Built deliverable; should have independent digest/provenance |
flowchart TD
C[Commit SHA] -- pointed to by --> T[Git tag v1.4.0]
T -- selected by --> R[GitHub Release object]
R -- describes --> N[Release notes]
R -- distributes --> A[Uploaded assets]
T -- snapshots --> S[GitHub-generated source ZIP/TAR]
A -- verify with --> D[Digest / attestation]
Every arrow is a claim you should verify. The release page cannot repair a tag that points at the wrong commit; a correct tag does not prove that an uploaded binary was built from it.
3. Draft, prerelease, and latest are release-object states
Draft means the Release object is not yet published. Drafts are useful for assembling notes and assets before the release becomes visible as a normal published release. Prerelease marks a published release as not yet suitable for general production use. Latest is a GitHub designation used for the repository’s current full release; drafts and prereleases cannot be the latest release through the current REST model.
Do not confuse “latest” with “greatest commit on main.”
A release can target an older commit intentionally, and support
branches may publish versions after newer development has continued
elsewhere.
4. Tag target, release branch, and support line are different relationships
A release ultimately keys off a tag. If you run
gh release create for a tag that does not exist, GitHub
CLI can create that tag from the default branch or from
--target. In a governed process, prefer creating and
inspecting the tag explicitly, then use --verify-tag so
release creation fails rather than silently inventing a tag at an
unintended commit.
A branch such as release/1.x is a support line, not a
release identity. You might cut v1.4.1 from that branch
while main develops v2.0. The tag freezes the version
identity; the branch remains movable development state.
5. Release notes are an operational interface, not decoration
Manual notes let maintainers explain upgrades, risks, migrations,
known issues, rollback steps, and support implications. GitHub can
also automatically generate notes from merged pull requests,
contributors, and configured categories. A
.github/release.yml file can group or exclude changes
using PR labels and authors.
Generated notes are only as useful as the metadata feeding them. If teams label PRs inconsistently, generated notes can omit or misclassify important changes. Always review generated output before publishing.
6. Uploaded assets and generated source archives have different provenance
GitHub automatically offers ZIP and tar.gz source archives corresponding to the tag. These archives are generated from repository content; they are not the same thing as a CI-built binary you manually upload. Uploaded assets are separate release-asset records with names, sizes, download counts, and—through the current REST schema—a digest field.
The distinction matters for reproducibility. A source archive proves
what repository snapshot was packaged by GitHub; it does not prove
that app.exe or container.tar was built
from that snapshot with a particular toolchain. Keep build
provenance and hashes with the uploaded artifact.
7. Treat published versions as immutable—even when the platform would let you edit them
Without enforcement, Git lets an authorized actor move or delete tags and GitHub lets release managers replace assets. A disciplined release process still treats a published version name as immutable: corrections become a new version rather than silently changing what an existing version means.
GitHub now offers immutable releases. When enabled, a published release locks its associated tag and uploaded assets; GitHub also generates a release attestation containing the release tag, commit SHA, and assets. Drafts remain editable until publication. If an immutable release is deleted, the tag may then be deleted, but the same immutable-release tag name cannot be reused.
# Production verification after publishing an immutable release
gh release verify v1.4.0
gh release verify-asset v1.4.0 ./dist/app-v1.4.0.zip
gh release verify-asset validates the local asset
digest against the release attestation. It does not apply to
GitHub-generated source ZIP/tar archives, which are produced when
requested rather than stored as uploaded release assets.
8. Read-only inspection before release mutation
# Local/remote tag state
git tag --list --sort=-version:refname
git ls-remote --tags origin
# Hosted Release state
gh release list -R OWNER/REPO --json tagName,name,isDraft,isPrerelease,isLatest,isImmutable,publishedAt
# Versioned REST: Release records are distinct from regular tags
gh api -H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2026-03-10" \
repos/OWNER/REPO/releases --paginate
# Inspect one tag target locally
git rev-list -n 1 v1.4.0
If a tag appears in git ls-remote --tags but not in the
Releases API list, that is not an inconsistency: a regular tag does
not automatically have a GitHub Release object.
9. DevOps connection: a Release is a supply-chain boundary
CI may produce an artifact; a GitHub Release decides how a version, notes, source snapshot, and uploaded assets are presented to consumers. Release governance must therefore answer: which commit is this, what was built, how was it verified, who may publish, which support line owns it, what does “latest” mean, and what happens when it is bad?
10. Lesson summary
Tags are Git refs; Releases are GitHub objects associated with tags. Draft/prerelease/latest are hosted release states. Source archives are generated repository snapshots, while uploaded assets are independent deliverables that need hashes/provenance. Generated notes depend on pull-request metadata. Production releases should be treated as immutable, and GitHub immutable releases can enforce that expectation.
Knowledge check
A tag exists on GitHub but gh release list does
not show it. Is the tag broken?
No. A Git tag can exist without any GitHub Release object. The tag API/Git refs and Releases API describe different resources.
Why should a governed release use
gh release create --verify-tag?
It makes release creation fail if the expected remote tag does not already exist, preventing accidental tag creation from the wrong default-branch/target state.
Is GitHub’s automatically generated source ZIP the same provenance object as a CI-built binary asset?
No. The source archive is generated from repository content at the tag; a built binary needs its own build identity, digest, and provenance evidence.
What changes when immutable releases are enabled?
After publication, the associated tag cannot be moved/deleted while the release exists and uploaded assets cannot be modified/deleted; GitHub also creates a release attestation.
Why can generated release notes still be incomplete even when generation succeeds?
Their categorization depends on merged PRs and metadata such as labels/authors. Inconsistent taxonomy can produce technically valid but operationally incomplete notes.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.