Release Management
Release management and tagging strategies for predictable, automated software releases
You are an expert in release management and tagging strategies for predictable, automated software releases. ## Key Points - `MAJOR.MINOR.PATCH` (e.g., `2.4.1`) - MAJOR — incompatible API changes - MINOR — backward-compatible new features - PATCH — backward-compatible bug fixes - Automate releases with semantic-release or similar tooling so that versioning and changelog generation are deterministic and not dependent on human memory - Use annotated tags (not lightweight tags) for releases so the tag carries author, date, and a message - Include a rollback plan: tag the previous release so reverting is a single `git revert` or redeployment of the prior tag - Tagging before CI passes, which creates a release artifact that may be broken - Forgetting to push tags to the remote (`git push` does not push tags by default without `--tags`) ## Quick Example ```bash # Using conventional-changelog CLI npx conventional-changelog -p angular -i CHANGELOG.md -s # Using git log directly git log v1.1.0..v1.2.0 --pretty=format:"- %s (%h)" --no-merges ```
skilldb get git-workflow-skills/Release ManagementFull skill: 150 linesRelease Management — Git Workflows
You are an expert in release management and tagging strategies for predictable, automated software releases.
Overview
Release management encompasses the processes and tooling for versioning, tagging, generating changelogs, and shipping software. A well-structured release process reduces human error, provides clear traceability, and enables rollbacks when issues arise.
Core Concepts
Semantic Versioning (semver):
MAJOR.MINOR.PATCH(e.g.,2.4.1)- MAJOR — incompatible API changes
- MINOR — backward-compatible new features
- PATCH — backward-compatible bug fixes
Git tags:
# Lightweight tag
git tag v1.0.0
# Annotated tag (preferred — stores author, date, message)
git tag -a v1.0.0 -m "Release 1.0.0: initial stable release"
# Push tags to remote
git push origin v1.0.0
git push origin --tags
# List tags matching a pattern
git tag -l "v2.*"
# Delete a tag (local + remote)
git tag -d v1.0.0-beta
git push origin --delete v1.0.0-beta
Changelog generation:
# Using conventional-changelog CLI
npx conventional-changelog -p angular -i CHANGELOG.md -s
# Using git log directly
git log v1.1.0..v1.2.0 --pretty=format:"- %s (%h)" --no-merges
Implementation Patterns
Automated release with semantic-release:
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Manual release workflow with a release branch:
# Create release branch from develop
git checkout -b release/2.0.0 develop
# Bump version
npm version 2.0.0 --no-git-tag-version
git commit -am "chore: bump version to 2.0.0"
# After QA passes, merge to main and tag
git checkout main
git merge --no-ff release/2.0.0
git tag -a v2.0.0 -m "Release 2.0.0"
git push origin main --tags
# Back-merge into develop
git checkout develop
git merge --no-ff release/2.0.0
git push origin develop
GitHub release creation:
# Create a release from an existing tag
gh release create v2.0.0 --title "v2.0.0" --generate-notes
# Create with specific changelog
gh release create v2.0.0 --title "v2.0.0" --notes-file CHANGELOG.md
# Upload build artifacts
gh release upload v2.0.0 dist/*.tar.gz
Core Philosophy
Release management is the discipline of making software delivery predictable, traceable, and reversible. A good release process answers three questions at any point in time: "what version is deployed?", "what changed since the last release?", and "how do I roll back if something goes wrong?" When these questions have instant, unambiguous answers — because version numbers are deterministic, changelogs are generated from commit history, and prior releases are tagged and deployable — the entire delivery pipeline becomes a source of confidence rather than anxiety.
Automation is not a convenience in release management — it is a correctness requirement. A human deciding version numbers will eventually get it wrong: shipping a breaking change as a patch, forgetting to update the changelog, or tagging before CI passes. Automated release tools (semantic-release, release-please) derive the version from commit history, generate the changelog from commit messages, create the git tag, and publish the package — all as a deterministic pipeline triggered by merging to main. This eliminates an entire category of human error and frees engineers to focus on the code, not the ceremony.
Git tags are the anchor of a release. A tag is an immutable pointer to a specific commit, which means it captures exactly what source code produced a given release. Annotated tags (which carry author, date, and message metadata) are preferred over lightweight tags because they are first-class git objects that can be verified and queried. The tag is what makes rollback possible: deploying a previous version is as simple as checking out the prior tag and redeploying. Without tags, "roll back to the last working version" becomes an archaeological exercise in CI build history.
Anti-Patterns
-
Manual version number decisions. Having a human decide whether a release is 2.3.1 or 2.4.0 introduces subjectivity and error. Use Conventional Commits with semantic-release to derive the version deterministically from the commit types:
featbumps minor,fixbumps patch,BREAKING CHANGEbumps major. -
Tagging before CI passes. Creating a release tag before the full CI pipeline (tests, lint, build, security scan) completes means the tag may point to a broken build. Always tag after CI confirms the commit is releasable, ideally as part of the automated release pipeline.
-
Forgetting to push tags. Running
git tag v1.0.0locally but notgit push origin v1.0.0means the tag exists only on one machine. Other developers and CI cannot see it, and if the local machine is lost, the tag is gone. Push tags immediately after creating them, or better, let CI create and push tags automatically. -
No changelog. Shipping releases without a changelog means consumers (internal or external) have no way to know what changed, what to test, or what might break. Generate changelogs automatically from commit messages so every release has a human-readable summary of changes.
-
Lightweight tags instead of annotated tags. Lightweight tags are just pointers with no metadata — no author, no date, no message. Annotated tags (
git tag -a) store this metadata, making it possible to know who created the release and when. Always use annotated tags for releases.
Best Practices
- Automate releases with semantic-release or similar tooling so that versioning and changelog generation are deterministic and not dependent on human memory
- Use annotated tags (not lightweight tags) for releases so the tag carries author, date, and a message
- Include a rollback plan: tag the previous release so reverting is a single
git revertor redeployment of the prior tag
Common Pitfalls
- Tagging before CI passes, which creates a release artifact that may be broken
- Forgetting to push tags to the remote (
git pushdoes not push tags by default without--tags)
Install this skill directly: skilldb add git-workflow-skills
Related Skills
Code Review
Code review best practices for constructive, efficient pull request reviews
Conventional Commits
Conventional Commits specification for structured, machine-readable commit messages
Git Bisect Debug
Debugging with git bisect and advanced git log techniques to pinpoint regressions
Git Hooks
Git hooks automation with Husky and lint-staged for pre-commit quality gates
Gitflow
Gitflow branching model for structured release-oriented development workflows
Monorepo Management
Monorepo strategies with Nx and Turborepo for scalable multi-project repositories