Git Tags and GitHub Releases
What are Git Tags?
Tags are references to specific points in a repository's history. They're commonly used to mark release versions.
Two types of tags:
- Lightweight tags: Simple pointers to commits
- Annotated tags: Full objects with metadata (recommended for releases)
Creating Tags
Lightweight Tag
Create lightweight tag
git tag v1.0.0
This creates a tag pointing to the current commit.
Annotated Tag
Create annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0"
Annotated tags include:
- Tagger name and email
- Tagging date
- Message describing the release
Tag Specific Commit
Tag a past commit
git tag -a v1.0.0 <commit-hash> -m "Release version 1.0.0"
Viewing Tags
List all tags
git tag
List tags matching pattern
git tag -l "v1.*"
# Output: v1.0.0, v1.1.0, v1.2.0
Show tag details
git show v1.0.0
Shows who created the tag, when, and the tagged commit.
Semantic Versioning
Follow semantic versioning format: MAJOR.MINOR.PATCH
- MAJOR (1.0.0): Incompatible API changes
- MINOR (1.1.0): New features, backward compatible
- PATCH (1.0.1): Bug fixes
Examples
v0.1.0 // Initial release
v1.0.0 // First production release
v1.1.0 // New features added
v1.1.1 // Bug fix
v2.0.0 // Breaking changes
v1.0.0-rc.1 // Release candidate
v1.0.0-beta.1 // Beta version
Pushing Tags
Push Single Tag
Push specific tag
git push origin v1.0.0
Push All Tags
Push all tags to remote
git push origin --tags
Push Tags and Commits
Push everything
git push origin main --tags
Deleting Tags
Delete Local Tag
Delete local tag
git tag -d v1.0.0
Delete Remote Tag
Delete tag on remote
git push origin --delete v1.0.0
# or
git push origin :v1.0.0
GitHub Releases
A release is a GitHub feature built on top of tags. It adds release notes, assets, and downloadable packages.
Create Release via GitHub Web UI
- Go to repository → Releases → "Create a new release"
- Select a tag or create a new one
- Add release title and description
- (Optional) Upload binary files, source code, etc.
- Mark as pre-release if needed
- Publish release
Create Release via CLI
Create release with gh CLI
gh release create v1.0.0 --title "Version 1.0.0" --notes "New features and bug fixes"
Create release with file uploads
gh release create v1.0.0 \
--title "Version 1.0.0" \
--notes "Release notes here" \
dist/app.zip \
dist/app.exe
Release Workflow
Complete Release Process
Complete release workflow
# 1. Make sure main branch is up-to-date
git checkout main
git pull origin main
# 2. Update version in package.json
vim package.json
# Change "version": "1.0.0"
# 3. Create a release commit
git add package.json
git commit -m "Release: version 1.0.0"
# 4. Create annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0
## What's New
- Feature 1
- Feature 2
- Bug fixes"
# 5. Push commit and tag
git push origin main
git push origin v1.0.0
# 6. Create GitHub release
gh release create v1.0.0 --title "Version 1.0.0" --notes-file RELEASE_NOTES.md
Release Notes Best Practices
RELEASE_NOTES.md template
# Version 1.0.0
## 🎉 New Features
- User authentication system
- Dashboard redesign
- Advanced search capabilities
## 🔧 Improvements
- Performance optimization (50% faster)
- Better error messages
- Improved documentation
## 🐛 Bug Fixes
- Fixed login redirect issue
- Fixed memory leak in data processor
- Resolved race condition in cache
## 🚨 Breaking Changes
- Removed deprecated API endpoints
- Changed database schema format
## 📦 Dependencies
- Updated React to v18.0.0
- Updated Express to v4.18.0
## ⚠️ Known Issues
- Large file uploads may timeout (working on fix)
- Dark mode not supported on older browsers
## 🙏 Credits
Thanks to [@contributor1](link) and [@contributor2](link) for their contributions!
Pre-release and Beta Versions
Create pre-release version
git tag -a v2.0.0-beta.1 -m "Beta release for v2.0.0"
git tag -a v2.0.0-rc.1 -m "Release candidate 1"
Mark as pre-release on GitHub
gh release create v2.0.0-beta.1 \
--title "v2.0.0 Beta 1" \
--prerelease \
--notes "Testing phase for v2.0.0"
Automated Versioning
Using tools to automate version bumping:
Using semantic-release (npm)
npm install --save-dev semantic-release
Automatically:
- Analyzes commits (conventional commits)
- Determines version bump (major/minor/patch)
- Updates version in package.json
- Creates tag and release
- Publishes to npm
Conventional Commits
Structure commits for automation:
feat: add user authentication
fix: resolve login redirect bug
docs: update API documentation
chore: update dependencies
perf: optimize database queries
Git Tag Aliases
Create shortcuts in .gitconfig:
Set up git aliases
git config --global alias.tag-release '!git tag -a $1 -m "Release $1"'
git config --global alias.release '!git push origin main && git push origin --tags'
Usage:
git tag-release v1.0.0
git release
Comparing Versions
Compare two tags
git diff v1.0.0 v1.1.0
See logs between tags
git log v1.0.0..v1.1.0 --oneline
Count commits between versions
git log v1.0.0..v1.1.0 --oneline | wc -l
Real-World Example
Complete release example
#!/bin/bash
# release.sh - Automated release script
VERSION=$1
BRANCH="main"
if [ -z "$VERSION" ]; then
echo "Usage: ./release.sh <version>"
exit 1
fi
# Validate version format
if ! [[ $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version format. Use: v1.0.0"
exit 1
fi
# Update to latest main
git checkout $BRANCH
git pull origin $BRANCH
# Update package.json version
CLEAN_VERSION=${VERSION:1} # Remove 'v' prefix
npm version $CLEAN_VERSION
# Create annotated tag
git tag -a $VERSION -m "Release $VERSION"
# Push to remote
git push origin $BRANCH
git push origin $VERSION
# Create GitHub release
gh release create $VERSION \
--title "Release $VERSION" \
--notes "See CHANGELOG.md for details"
echo "✅ Release $VERSION complete!"
Downstream: Using Released Versions
Install from Specific Tag
Clone specific tag
git clone --branch v1.0.0 https://github.com/user/repo.git
Download Release Assets
Download release asset
gh release download v1.0.0 --pattern "*.zip"
Best Practices
- Use semantic versioning consistently
- Always use annotated tags for releases
- Tag on main branch only (stable code)
- Write descriptive release notes
- Include breaking changes prominently
- Test before tagging (build, tests, linting)
- Use conventional commits for automation
- Automate versioning when possible
- Keep CHANGELOG.md updated
- Sign tags for security (git tag -s)
Key Takeaways
- Tags mark specific points in history
- Releases are GitHub's way to package tags
- Semantic versioning communicates what changed
- Annotated tags include metadata
- Conventional commits enable automation
- Release notes help users understand changes
- Pre-releases let users test before stable release