16 KiB
Git Branching Strategy
Overview
This document defines the git branching strategy for StarPunk. The strategy balances simplicity with discipline, appropriate for a personal/small-team project while supporting semantic versioning and clean releases.
Philosophy: Keep it simple. Minimize long-lived branches. Integrate frequently.
Primary Branch
Branch: main
Purpose: The primary development branch and source of truth
Characteristics:
- Always contains the latest development code
- Should be stable and pass all tests
- Protected from direct commits (use pull requests)
- Tagged for releases
- Never rewritten or force-pushed
Version state: Development version (0.x.y) until first stable release (1.0.0)
Branch Types
Feature Branches
Naming: feature/<description> or <description>
Purpose: Develop new features or enhancements
Lifecycle:
- Branch from:
main - Merge into:
main - Delete after: Merged or abandoned
Examples:
feature/micropub-endpointfeature/rss-feedindieauth-integrationnote-markdown-support
Workflow:
# Create feature branch
git checkout -b feature/micropub-endpoint main
# Work on feature
git add .
git commit -m "Add micropub endpoint skeleton"
# Keep updated with main
git fetch origin
git rebase origin/main
# When ready, create pull request or merge
git checkout main
git merge feature/micropub-endpoint
# Delete feature branch
git branch -d feature/micropub-endpoint
Fix Branches
Naming: fix/<description> or bugfix/<description>
Purpose: Fix bugs in development code
Lifecycle:
- Branch from:
main - Merge into:
main - Delete after: Merged
Examples:
fix/slug-generation-unicodebugfix/rss-invalid-xmlfix/auth-redirect-loop
Workflow: Same as feature branches
Hotfix Branches
Naming: hotfix/<version>-<description>
Purpose: Critical fixes to production releases (post-1.0.0)
Lifecycle:
- Branch from: Release tag (e.g.,
v1.0.0) - Merge into:
main - Tag as new release:
v1.0.1 - Delete after: Released
Examples:
hotfix/1.0.1-security-path-traversalhotfix/1.1.1-rss-encoding
Workflow:
# Create hotfix from release tag
git checkout -b hotfix/1.0.1-security-fix v1.0.0
# Fix the issue
git commit -m "Fix security vulnerability"
# Update version
# Edit starpunk/__init__.py: __version__ = "1.0.1"
# Update CHANGELOG.md
git commit -m "Bump version to 1.0.1"
# Tag the hotfix
git tag -a v1.0.1 -m "Hotfix 1.0.1: Security vulnerability fix"
# Merge into main
git checkout main
git merge hotfix/1.0.1-security-fix
# Push
git push origin main v1.0.1
# Delete hotfix branch
git branch -d hotfix/1.0.1-security-fix
Release Branches (Optional)
Naming: release/<version>
Purpose: Prepare for release (testing, docs, version bumps)
Used when: Release preparation requires multiple commits and testing
Note: For V1 (simple project), we likely don't need release branches. We can prepare releases directly on main or feature branches.
If used:
# Create release branch
git checkout -b release/1.0.0 main
# Prepare release
# - Update version numbers
# - Update CHANGELOG.md
# - Update documentation
# - Final testing
git commit -m "Prepare release 1.0.0"
# Tag
git tag -a v1.0.0 -m "Release 1.0.0: First stable release"
# Merge to main
git checkout main
git merge release/1.0.0
# Push
git push origin main v1.0.0
# Delete release branch
git branch -d release/1.0.0
Branch Naming Conventions
Format
Preferred: <type>/<description>
Types:
feature/- New featuresfix/- Bug fixesbugfix/- Bug fixes (alternative)hotfix/- Production hotfixesdocs/- Documentation onlyrefactor/- Code refactoringtest/- Test additions/changeschore/- Maintenance tasks
Description:
- Use lowercase
- Use hyphens to separate words
- Be descriptive but concise
- Reference issue number if applicable
Examples
Good:
feature/micropub-create-actionfix/rss-pubdate-timezonedocs/api-documentationrefactor/note-storage-layertest/slug-generation-edge-caseschore/update-dependencies
Acceptable (simple description):
micropub-endpointrss-feedauth-integration
Avoid:
my-feature(too vague)feature/Feature1(not descriptive)fix_bug(use hyphens)FEATURE-MICROPUB(use lowercase)
Workflows
Development Workflow (Pre-1.0)
For single developer:
- Work directly on
mainfor small changes - Use feature branches for larger features
- Commit frequently with clear messages
- Tag development milestones (e.g.,
v0.1.0)
For multiple developers:
- Always use feature branches
- Create pull requests
- Review before merging
- Delete feature branches after merge
Feature Development
# Start feature
git checkout -b feature/new-feature main
# Develop
git add file.py
git commit -m "Implement core functionality"
# Keep updated
git fetch origin
git rebase origin/main
# Finish
git checkout main
git merge feature/new-feature
git push origin main
git branch -d feature/new-feature
Release Workflow
For development releases (0.x.y):
# Ensure on main
git checkout main
# Update version
# Edit starpunk/__init__.py
# Update CHANGELOG.md
# Commit
git add starpunk/__init__.py CHANGELOG.md
git commit -m "Bump version to 0.2.0"
# Tag
git tag -a v0.2.0 -m "Development release 0.2.0: Phase 1.2 complete"
# Push
git push origin main v0.2.0
For stable releases (1.0.0+):
# Option 1: Direct on main (simple)
git checkout main
# Update version, changelog, documentation
git commit -m "Prepare release 1.0.0"
git tag -a v1.0.0 -m "Release 1.0.0: First stable release"
git push origin main v1.0.0
# Option 2: Using release branch (if needed)
git checkout -b release/1.0.0 main
# Prepare release
git commit -m "Prepare release 1.0.0"
git tag -a v1.0.0 -m "Release 1.0.0: First stable release"
git checkout main
git merge release/1.0.0
git push origin main v1.0.0
git branch -d release/1.0.0
Hotfix Workflow
# Create from release tag
git checkout -b hotfix/1.0.1-critical-fix v1.0.0
# Fix
git commit -m "Fix critical bug"
# Version bump
git commit -m "Bump version to 1.0.1"
# Tag
git tag -a v1.0.1 -m "Hotfix 1.0.1: Critical bug fix"
# Merge to main
git checkout main
git merge hotfix/1.0.1-critical-fix
# Push
git push origin main v1.0.1
# Clean up
git branch -d hotfix/1.0.1-critical-fix
Branch Protection Rules
Main Branch Protection
For solo development:
- Recommended but not enforced via GitHub
- Self-discipline: treat
mainas protected - Don't force push
- Don't rewrite history
For team development:
- Require pull request reviews
- Require status checks to pass
- Prevent force push
- Prevent deletion
GitHub settings (when ready):
Settings → Branches → Add branch protection rule
Branch name pattern: main
Protect matching branches:
☑ Require a pull request before merging
☑ Require approvals (1)
☑ Require status checks to pass before merging
☑ Require branches to be up to date before merging
☑ Require conversation resolution before merging
☑ Do not allow bypassing the above settings
☐ Allow force pushes (NEVER enable)
☐ Allow deletions (NEVER enable)
Tagging Strategy
Tag Format
Version tags: vMAJOR.MINOR.PATCH[-PRERELEASE]
Examples:
v0.1.0- Development releasev1.0.0- First stable releasev1.0.1- Patch releasev1.1.0- Minor releasev2.0.0- Major releasev1.0.0-alpha.1- Pre-release
Tag Types
Annotated tags (ALWAYS use for releases):
git tag -a v1.0.0 -m "Release 1.0.0: First stable release"
Why annotated:
- Contains tagger, date, message
- Can include release notes
- Can be GPG signed
- Treated as full Git objects
- Better for releases
Lightweight tags (NEVER use for releases):
git tag v1.0.0 # Don't do this for releases
Tag Messages
Format:
Release MAJOR.MINOR.PATCH: <Brief description>
[Optional longer description]
[Release highlights]
Examples:
git tag -a v1.0.0 -m "Release 1.0.0: First stable release
Complete IndieWeb CMS implementation with:
- IndieAuth authentication
- Micropub publishing endpoint
- RSS feed generation
- File-based note storage
- Markdown support"
git tag -a v1.0.1 -m "Hotfix 1.0.1: Security vulnerability fix"
git tag -a v0.2.0 -m "Development release 0.2.0: Phase 1.2 complete"
Viewing Tags
# List all tags
git tag
# List tags with messages
git tag -n
# Show tag details
git show v1.0.0
# List tags matching pattern
git tag -l "v1.0.*"
Pushing Tags
# Push specific tag
git push origin v1.0.0
# Push all tags
git push origin --tags
# Delete remote tag (if needed)
git push origin :refs/tags/v1.0.0
Integration with Semantic Versioning
Version-to-Branch Mapping
Development phase (0.x.y):
- Work on
main - Tag development milestones:
v0.1.0,v0.2.0, etc. - Breaking changes allowed
Stable releases (1.x.y):
- Work on
mainor feature branches - Tag stable releases:
v1.0.0,v1.1.0, etc. - Breaking changes require major version bump
Major releases (2.0.0+):
- Work on
mainor feature branches - Tag major releases:
v2.0.0,v3.0.0, etc. - Document breaking changes thoroughly
Branch-to-Release Flow
feature/micropub → main → v0.1.0 (development)
feature/rss → main → v0.2.0 (development)
feature/auth → main → v0.3.0 (development)
main → v1.0.0 (stable)
fix/bug → main → v1.0.1 (patch)
feature/new → main → v1.1.0 (minor)
feature/breaking → main → v2.0.0 (major)
Common Scenarios
Scenario 1: Developing a New Feature
# Create feature branch
git checkout -b feature/micropub-endpoint main
# Develop
git commit -am "Add micropub create action"
git commit -am "Add micropub update action"
# Keep updated with main
git fetch origin
git rebase origin/main
# Merge when ready
git checkout main
git merge feature/micropub-endpoint
# Push and clean up
git push origin main
git branch -d feature/micropub-endpoint
Scenario 2: Releasing a Development Version
# Update version
echo '__version__ = "0.2.0"' > starpunk/__init__.py
# Update changelog
# Edit CHANGELOG.md
# Commit
git commit -am "Bump version to 0.2.0"
# Tag
git tag -a v0.2.0 -m "Development release 0.2.0"
# Push
git push origin main v0.2.0
Scenario 3: First Stable Release
# Final preparations on main
git commit -am "Update documentation for 1.0.0"
# Version bump
echo '__version__ = "1.0.0"' > starpunk/__init__.py
# Edit CHANGELOG.md
git commit -am "Bump version to 1.0.0"
# Tag
git tag -a v1.0.0 -m "Release 1.0.0: First stable release"
# Push
git push origin main v1.0.0
Scenario 4: Critical Production Bug
# Create hotfix from last release
git checkout -b hotfix/1.0.1-security-fix v1.0.0
# Fix the bug
git commit -am "Fix security vulnerability"
# Version bump
echo '__version__ = "1.0.1"' > starpunk/__init__.py
# Edit CHANGELOG.md
git commit -am "Bump version to 1.0.1"
# Tag
git tag -a v1.0.1 -m "Hotfix 1.0.1: Security vulnerability fix"
# Merge to main
git checkout main
git merge hotfix/1.0.1-security-fix
# Push
git push origin main v1.0.1
# Clean up
git branch -d hotfix/1.0.1-security-fix
Scenario 5: Multiple Features in Progress
# Developer 1: Feature A
git checkout -b feature/feature-a main
# Work on feature A
# Developer 2: Feature B
git checkout -b feature/feature-b main
# Work on feature B
# Feature A finishes first
git checkout main
git merge feature/feature-a
git push origin main
# Feature B rebases onto updated main
git checkout feature/feature-b
git rebase origin/main
# Continue work
# Feature B finishes
git checkout main
git merge feature/feature-b
git push origin main
Best Practices
Do
- Commit often with clear messages
- Pull before push to avoid conflicts
- Rebase feature branches to keep history clean
- Delete merged branches to reduce clutter
- Tag releases with annotated tags
- Write descriptive commit messages (50 char summary, then details)
- Test before merging to main
- Use pull requests for team development
- Keep main stable - always passing tests
- Document breaking changes in commits and changelog
Don't
- Never force push to
main - Never rewrite history on
main - Don't commit directly to
main(team development) - Don't merge broken code - tests must pass
- Don't create long-lived branches - integrate frequently
- Don't use lightweight tags for releases
- Don't forget to push tags after creating them
- Don't merge without updating from origin first
- Don't commit secrets or sensitive data
- Don't skip version bumps before tagging
Commit Message Format
Format:
<type>: <summary> (50 chars or less)
<optional detailed description>
<optional footer: references, breaking changes>
Types:
feat:New featurefix:Bug fixdocs:Documentationstyle:Formatting, whitespacerefactor:Code refactoringtest:Adding testschore:Maintenance tasks
Examples:
feat: Add Micropub create endpoint
Implements the create action for Micropub specification.
Supports h-entry posts with content, name, and published properties.
Refs: #15
fix: Correct RSS pubDate timezone handling
Previously used local timezone, now uses UTC as per RSS spec.
Fixes: #23
docs: Update installation instructions
chore: Bump version to 1.0.0
Troubleshooting
Problem: Merge Conflict
# During merge
git merge feature/my-feature
# CONFLICT (content): Merge conflict in file.py
# Resolve conflicts
# Edit file.py, resolve conflicts
git add file.py
git commit -m "Merge feature/my-feature"
Problem: Accidentally Committed to Main
# If not pushed yet
git reset HEAD~1 # Undo last commit, keep changes
git stash # Save changes
git checkout -b feature/my-feature # Create feature branch
git stash pop # Apply changes
git commit -am "Feature implementation"
Problem: Need to Update Feature Branch
# Option 1: Rebase (clean history)
git checkout feature/my-feature
git rebase origin/main
# Option 2: Merge (preserves history)
git checkout feature/my-feature
git merge origin/main
Problem: Wrong Tag Name
# Delete local tag
git tag -d v1.0.0
# Delete remote tag
git push origin :refs/tags/v1.0.0
# Create correct tag
git tag -a v1.0.1 -m "Release 1.0.1"
git push origin v1.0.1
References
Internal Documentation
- Versioning Strategy - Version numbering scheme
- ADR-008: Versioning Strategy - Versioning decision rationale
- ADR-009: Git Branching Strategy - This strategy's decision record
- Development Setup - Development environment
External Resources
- Git Branching Model - Git Flow (inspiration, not followed exactly)
- GitHub Flow - Simpler flow (closer to our approach)
- Semantic Versioning - Version numbering
- Git Documentation - Official Git documentation
Document: Git Branching Strategy Version: 1.0 Last Updated: 2025-11-18 Status: Active