This guide provides step-by-step instructions for cleaning up the repository and creating release tags, with special considerations for different environments (local VS Code, CI/CD, etc.).
Creating a release tag involves:
- Ensuring the repository is in a clean state
- Verifying all tests pass and quality checks are green
- Creating an annotated Git tag
- Pushing the tag to GitHub
- (Optional) Creating a GitHub release
Before tagging a release:
- All tests pass (
pytest -v) - Code quality checks pass (
black --check .,ruff check .,mypy src) - CHANGELOG.md is updated with the release version and date
- All intended changes are committed and pushed
- CI/CD pipeline is green
This method works best in CI/CD environments or when you have a clean working directory.
# Check current status
git status
# Should show "nothing to commit, working tree clean"# Check current branch
git branch --show-current
# If you're on a feature branch and want to tag from main:
# Note: In CI/CD, main branch may not exist locally
git log --oneline -5 # Verify you're on the right commit# Create an annotated tag (preferred for releases)
git tag -a v0.1.0 -m "Release version 0.1.0
- Comprehensive documentation
- Code repair strategy implementation
- VS Code integration
- 100% test coverage
"
# Verify the tag was created
git tag -l
git show v0.1.0# Push the tag to GitHub
git push origin v0.1.0
# Or push all tags
git push origin --tagsUse this method when working locally in VS Code with potential uncommitted changes.
# Check if there are uncommitted changes
git status -s
# If there are changes you want to keep:
git stash push -u -m "WIP: before tagging v0.1.0"
# If status shows nothing, skip the stash step
# (attempting to stash with no changes will fail)# Remove Python cache and build artifacts (safe)
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
find . -type f -name ".coverage" -delete 2>/dev/null || true
rm -rf htmlcov/ .mypy_cache/ .ruff_cache/ 2>/dev/null || true
# Or use git clean for more aggressive cleanup
# WARNING: This removes ALL untracked files!
# git clean -xdf # Use with caution!# Fetch latest from origin
git fetch origin 2>/dev/null || echo "Fetch failed, continuing with local state"
# Try to pull if on a branch that tracks remote
git pull --ff-only origin $(git branch --show-current) 2>/dev/null || echo "Pull not needed or branch doesn't track remote"
# Alternative: If you want to ensure you're on main
# git checkout main 2>/dev/null && git pull --ff-only origin main || echo "Main branch not available locally"Follow Steps 3-4 from Method 1 above.
# List stashes
git stash list
# Restore the most recent stash
git stash pop
# Or restore a specific stash
# git stash pop stash@{0}Use this for a completely clean slate (rarely needed).
# Save any uncommitted changes as a patch
git diff > /tmp/my-changes-$(date +%Y%m%d-%H%M%S).patch
# Or commit everything to a backup branch
git checkout -b backup-before-tag-$(date +%Y%m%d-%H%M%S)
git add .
git commit -m "Backup before tagging"
git checkout - # Return to previous branch# Fetch all changes
git fetch origin
# Reset to match remote branch exactly
git reset --hard origin/$(git branch --show-current)
# Clean all untracked files
git clean -xdfFollow Steps 3-4 from Method 1 above.
Symptom: No local changes to save
Solution: This is normal when working tree is clean. Skip the stash step and proceed to tagging.
# Only stash if there are changes
if [[ -n $(git status -s) ]]; then
git stash push -u -m "pre-tag cleanup"
else
echo "No changes to stash, proceeding..."
fiSymptom: Authentication failed or fatal: couldn't find remote ref
Solutions:
-
Authentication Issue: Configure credentials or use SSH instead of HTTPS
# Check remote URL git remote -v # Switch to SSH if needed git remote set-url origin git@github.com:SynTechRev/SynTechRev-PolyCodCal.git
-
Branch doesn't exist remotely: Create it or tag from current branch
# Check available remote branches git branch -r # Tag from current branch instead git tag -a v0.1.0 -m "Release v0.1.0"
-
In CI/CD environment: You may not need to pull at all
# CI/CD often checks out specific commits, not branches # Just create and push the tag git tag -a v0.1.0 -m "Release v0.1.0" git push origin v0.1.0
Symptom: Accidentally deleted configuration or local files
Prevention:
- Always ensure important files are tracked in Git
- Use
.gitignoreto protect local config files - Use more targeted cleanup commands first
Recovery:
# If files were committed, restore them
git checkout HEAD -- <filename>
# If files were never committed, check backupsSymptom: fatal: tag 'v0.1.0' already exists
Solutions:
-
Check existing tags:
git tag -l git show v0.1.0 # See what's in the existing tag -
Delete and recreate (if tag is only local):
git tag -d v0.1.0 git tag -a v0.1.0 -m "Release v0.1.0" -
Delete remote tag (use with caution!):
# Delete local tag git tag -d v0.1.0 # Delete remote tag git push origin :refs/tags/v0.1.0 # Create new tag git tag -a v0.1.0 -m "Release v0.1.0" git push origin v0.1.0
-
Use a different version number:
# If v0.1.0 is already released, use v0.1.1 or v0.2.0 git tag -a v0.1.1 -m "Release v0.1.1"
Symptom: .git/index.lock or permission errors
Solution:
# Remove lock file (only if no git operations are running!)
rm -f .git/index.lock
# Fix permissions if needed
chmod -R u+w .git/- Major (X.0.0): Breaking changes
- Minor (0.X.0): New features, backwards compatible
- Patch (0.0.X): Bug fixes, backwards compatible
# Good: Annotated tag with message
git tag -a v0.1.0 -m "Release v0.1.0 - Initial stable release"
# Avoid: Lightweight tag (no metadata)
git tag v0.1.0Ensure CHANGELOG.md has an entry for the version you're tagging:
## [0.1.0] - 2025-10-11
### Added
- Feature A
- Feature B
### Fixed
- Bug fix C# Check the tag locally before pushing
git show v0.1.0
# Review the commit history
git log --oneline -10
# Ensure CI/CD passed on the commit you're taggingAfter pushing the tag, create a GitHub release:
- Go to:
https://github.com/SynTechRev/SynTechRev-PolyCodCal/releases/new - Select the tag:
v0.1.0 - Fill in release title:
Release v0.1.0 - Copy content from CHANGELOG.md for the release notes
- Attach any release artifacts if needed
- Publish release
Save this as scripts/create_release_tag.sh:
#!/bin/bash
# Create a release tag with proper checks
set -e # Exit on error
# Configuration
VERSION="${1:-}"
MESSAGE="${2:-Release $VERSION}"
# Validate input
if [[ -z "$VERSION" ]]; then
echo "Usage: $0 <version> [message]"
echo "Example: $0 v0.1.0 'Initial stable release'"
exit 1
fi
# Validate version format
if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: Version must be in format vX.Y.Z (e.g., v0.1.0)"
exit 1
fi
echo "Creating release tag: $VERSION"
echo "Message: $MESSAGE"
echo
# Check if tag already exists
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "Error: Tag $VERSION already exists"
echo "Use: git tag -d $VERSION # to delete local tag"
exit 1
fi
# Check working directory is clean
if [[ -n $(git status -s) ]]; then
echo "Warning: Working directory has uncommitted changes"
git status -s
read -p "Continue anyway? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
# Clean build artifacts
echo "Cleaning build artifacts..."
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
rm -rf .pytest_cache htmlcov .coverage .mypy_cache .ruff_cache 2>/dev/null || true
# Create the tag
echo "Creating annotated tag..."
git tag -a "$VERSION" -m "$MESSAGE"
# Show the tag
echo
echo "Tag created successfully:"
git show "$VERSION" --quiet
# Ask to push
echo
read -p "Push tag to origin? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
git push origin "$VERSION"
echo
echo "Tag pushed successfully!"
echo "Create GitHub release at:"
echo "https://github.com/SynTechRev/SynTechRev-PolyCodCal/releases/new?tag=$VERSION"
else
echo "Tag created locally but not pushed."
echo "To push later: git push origin $VERSION"
fiMake it executable:
chmod +x scripts/create_release_tag.shUsage:
# Create and push v0.1.0 tag
./scripts/create_release_tag.sh v0.1.0 "Initial stable release with comprehensive documentation"# List all tags
git tag -l
# Show tag details
git show v0.1.0
# Create annotated tag
git tag -a v0.1.0 -m "Release v0.1.0"
# Push specific tag
git push origin v0.1.0
# Push all tags
git push origin --tags
# Delete local tag
git tag -d v0.1.0
# Delete remote tag
git push origin :refs/tags/v0.1.0
# Check out specific tag
git checkout v0.1.0
# Create branch from tag
git checkout -b hotfix-v0.1.1 v0.1.0In VS Code terminal, use the safest approach:
# 1. Check status
git status
# 2. Clean artifacts only (safe)
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
# 3. Create tag
git tag -a v0.1.0 -m "Release v0.1.0"
# 4. Push tag (may require authentication setup in VS Code)
git push origin v0.1.0The key to successful tagging is:
- Verify clean state - No uncommitted changes (or stash them)
- Clean artifacts - Remove build files, not source files
- Create annotated tag - Include version and description
- Push to remote - Share with team and trigger CI/CD
- Create GitHub release - Official release with notes
For most cases, especially in CI/CD, you only need:
git tag -a v0.1.0 -m "Release v0.1.0"
git push origin v0.1.0The complicated steps are only needed when dealing with local changes, authentication issues, or repository cleanup needs.