Tags and Release
Software teams produce many versions over time. Some versions stay private. Some become formal releases. The difference between a tag and a release is important because they serve different purposes. A tag is a technical marker. A release is a public commitment.
A tag points to a specific commit in a Git repository. It should be immutable. Once a release tag is created, it should not be moved. That stability makes it a reliable reference for source code, audits, and comparisons.
A release is the publishing layer that sits on top of a tag. It often includes the tag, release notes, version information, and build artifacts. It tells users what is being delivered and why.
Why the Distinction Matters
Developers often use tags for internal tracking. Product teams use releases for communication. A tag alone may not explain what changed for customers. A release adds context, binaries, and instructions.
This separation creates clarity. Engineers can inspect the exact commit. Support teams can explain the version. Users can download the right build.
Tag Types and Their Tradeoffs
Git offers two main tag types.
- Lightweight tags are simple references to commits. They are fast and easy to create, but they lack metadata.
- Annotated tags include tagger information, dates, messages, and optional signatures. They are preferred for formal releases.
git tag -a v1.0.0 -m "Release version 1.0.0"
git tag v1.0.0-rc1
Common Tag Operations
git tag -a v1.0.0 -m "Release first stable version"
git tag v1.0.0-rc1
git tag
git tag -l "v1.*"
git show v1.0.0
git push origin v1.0.0
git push origin --tags
git tag -d v1.0.0
git push origin --delete v1.0.0
An important habit is to push tags explicitly. Git does not push tags by default. Teams should use git push origin --tags or push each release tag.
Turning a Tag into a Release
A release usually starts with a tag. The release process depends on the hosting platform. GitHub, GitLab, and similar tools provide release features.
A typical release package may include:
- Version label, such as
v2.1.0. - Release notes describing features, fixes, and known issues.
- Binary assets, such as executables, installers, or source archives.
- Pre-release marker for beta or unstable versions.
The usual flow is:
- Create a tag.
- Push the tag.
- Create a release from the tag.
- Add notes and assets.
- Publish.
Writing Useful Release Notes
Release notes should be clear and actionable. They should list new features, bug fixes, breaking changes, and upgrade steps. Good notes reduce confusion and support load.
Semantic Versioning
Many teams follow semantic versioning. The format is MAJOR.MINOR.PATCH.
- Major: incompatible API or behavior changes.
- Minor: backward-compatible new features.
- Patch: backward-compatible bug fixes.
For example, v2.3.1 indicates major version 2, minor version 3, and patch version 1.
Automating Release Workflows
Manual release processes can miss steps. CI can handle builds and publishing when a tag is pushed.
name: Release
on:
push:
tags:
- "v*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: make build
- uses: softprops/action-gh-release@v2
with:
files: dist/*
After this setup, pushing v1.2.0 can trigger the build and release process.
Best Practices
- Use annotated tags for formal releases.
- Sign important releases when possible.
- Follow semantic versioning consistently.
- Write useful release notes.
- Automate builds and publishing.
- Avoid rewriting published tags or releases.
Final Thoughts
Tags and releases work best together. The tag preserves the code reference. The release communicates the change. Used well, they create traceability, stability, and trust in the release process.