Skip to content

Cheatsheet: Releases and tags

Git stores snapshots. Every other command is just navigating those snapshots.

A tag is an immutable label on a specific snapshot.

Terminal window
# Create
git tag -a vX.Y.Z -m "Release vX.Y.Z: description" # current commit
git tag -a vX.Y.Z <commit-sha> -m "description" # specific commit
# Inspect
git tag # list all tags
git tag --sort=-v:refname # version-aware sort, descending
git tag --list 'v1.*' # filter by pattern
git show vX.Y.Z # full details
# Push
git push origin vX.Y.Z # one tag
git push origin --tags # all local tags
# Pull
git fetch --tags # download tags from remote
# Delete
git tag -d vX.Y.Z # local
git push origin --delete vX.Y.Z # remote
What kind of change since the last release?
Breaking (consumers must change their code)
-> bump MAJOR (vX.Y.Z -> v(X+1).0.0)
New feature, backward-compatible (consumers can opt in)
-> bump MINOR (vX.Y.Z -> vX.(Y+1).0)
Bug fix, backward-compatible (consumers don't need to know)
-> bump PATCH (vX.Y.Z -> vX.Y.(Z+1))
Pre-1.0?
-> API not yet stable; bumps are looser; aim for v1.0.0 when API stabilizes
vX.Y.Z-alpha.1 # earliest; expect bugs
vX.Y.Z-alpha.2 # iterate
vX.Y.Z-beta.1 # more stable; user testing
vX.Y.Z-beta.2
vX.Y.Z-rc.1 # release candidate; should be the final
vX.Y.Z-rc.2 # only if rc.1 broke
vX.Y.Z # the actual release
# vX.Y.Z - YYYY-MM-DD
## Highlights
One-paragraph summary. Lead with what users care about most.
## Breaking changes
- (only if there are any; otherwise omit)
## New features
- Feature description (#issue-or-pr-number)
## Improvements
- Performance, UX, or internal quality changes
## Bug fixes
- Description (#issue-or-pr-number)
## Migration notes
For users upgrading from vX-1.Y.Z:
- Step-by-step migration steps
## Contributors
Thanks to @user1, @user2, and N others.
  1. Bug fix where login redirected to wrong URL -> PATCH bump. Backward-compatible internal fix.
  2. New endpoint POST /api/v2/refunds (existing endpoints unchanged) -> MINOR bump. New feature, backward-compatible.
  3. Removed deprecated GET /api/v1/users-old -> MAJOR bump. Removing an endpoint breaks consumers still using it, regardless of how long it was deprecated.
  4. Changed default value of API parameter from false to true -> MAJOR bump. Behavior change that breaks existing consumers who relied on the default.
  5. Improved performance of internal function (no API change) -> PATCH bump. Internal change with no consumer-visible API impact.
  6. Renamed internal class but kept public API identical -> PATCH bump. No consumer-visible change; internal refactor.
  7. Added new optional field to JSON response (existing fields unchanged) -> MINOR bump. New feature consumers can opt into; backward-compatible (old consumers ignore the new field).
  8. Added new required field to request body (existing requests now fail) -> MAJOR bump. Breaking change; existing consumers must update their requests.

L11 introduces two powerful primitives:

  • Cherry-pick (git cherry-pick <commit>), apply a specific commit from one branch onto another. Used for hotfixes that need to go to both main + a release branch; backporting fixes to older versions; pulling specific commits without merging an entire branch.

  • Stash (git stash), save in-progress work without committing it. Used when you need to switch branches urgently but your working dir has uncommitted changes; pulling without committing the WIP; multi-tasking.

Both are tools for composing the L1-L10 primitives into advanced workflows. After L11, you have the full Phase 3 toolkit.