485 lines
14 KiB
Markdown
485 lines
14 KiB
Markdown
# ADR-009: Git Branching Strategy
|
|
|
|
## Status
|
|
|
|
Accepted
|
|
|
|
## Context
|
|
|
|
StarPunk needs a git branching strategy that supports:
|
|
|
|
1. **Semantic versioning workflow** - Moving from 0.x.y development through 1.0.0 stable release
|
|
2. **Single developer initially** - Optimized for solo work but scalable to small teams
|
|
3. **Clean release history** - Clear tags and versioning aligned with SemVer
|
|
4. **Hotfix capability** - Ability to patch production releases
|
|
5. **Minimal complexity** - Appropriate for indie project scale
|
|
6. **Development discipline** - Structure without bureaucracy
|
|
|
|
### Current State
|
|
|
|
The project just renamed its primary branch from `master` to `main` to align with modern Git conventions and industry best practices. This is a brand new repository with no commits yet, currently at version 0.1.0 (development phase).
|
|
|
|
### Requirements
|
|
|
|
The branching strategy must:
|
|
|
|
1. **Support semantic versioning** releases (0.1.0 → 1.0.0 → 1.0.1 → 1.1.0 → 2.0.0)
|
|
2. **Work for solo and team** development
|
|
3. **Enable clean releases** with proper tagging
|
|
4. **Allow hotfixes** to production versions
|
|
5. **Keep main branch stable** - always in working state
|
|
6. **Minimize long-lived branches** - integrate frequently
|
|
7. **Align with IndieWeb values** - simplicity, no lock-in
|
|
8. **Be well-documented** - clear workflows for common scenarios
|
|
|
|
## Decision
|
|
|
|
We will adopt a **simplified trunk-based development** strategy with feature branches and semantic versioning integration.
|
|
|
|
### Core Principles
|
|
|
|
1. **Single primary branch**: `main`
|
|
2. **Branch name**: `main` (not `master`)
|
|
3. **Feature branches**: Short-lived branches for features/fixes
|
|
4. **Direct tagging**: Tag `main` for releases
|
|
5. **Hotfix branches**: For production patches (post-1.0.0)
|
|
6. **No long-lived branches**: Integrate to main frequently
|
|
7. **Annotated tags**: Always use annotated tags for releases
|
|
|
|
### Branch Structure
|
|
|
|
**Primary branch**: `main`
|
|
- Single source of truth
|
|
- Always stable (tests pass)
|
|
- Tagged for releases
|
|
- Protected from force push
|
|
- Never rewritten
|
|
|
|
**Feature branches**: `feature/<description>` or `<description>`
|
|
- Branch from `main`
|
|
- Merge into `main`
|
|
- Short-lived (hours to days, not weeks)
|
|
- Deleted after merge
|
|
|
|
**Fix branches**: `fix/<description>` or `bugfix/<description>`
|
|
- Branch from `main`
|
|
- Merge into `main`
|
|
- Deleted after merge
|
|
|
|
**Hotfix branches**: `hotfix/<version>-<description>` (post-1.0.0 only)
|
|
- Branch from release tag (e.g., `v1.0.0`)
|
|
- Fix critical production bugs
|
|
- Tagged as new patch release (e.g., `v1.0.1`)
|
|
- Merged into `main`
|
|
- Deleted after release
|
|
|
|
**Release branches**: `release/<version>` (optional, rarely used)
|
|
- Only if release preparation requires multiple commits
|
|
- For V1, likely unnecessary (prepare on `main` or feature branch)
|
|
- Branch from `main`, merge back to `main`, tag, delete
|
|
|
|
### Branch Naming Conventions
|
|
|
|
**Preferred format**: `<type>/<description>`
|
|
|
|
**Types**:
|
|
- `feature/` - New features
|
|
- `fix/` or `bugfix/` - Bug fixes
|
|
- `hotfix/` - Production hotfixes
|
|
- `docs/` - Documentation only
|
|
- `refactor/` - Code refactoring
|
|
- `test/` - Test additions
|
|
- `chore/` - Maintenance tasks
|
|
|
|
**Description**:
|
|
- Lowercase with hyphens
|
|
- Descriptive but concise
|
|
- Example: `feature/micropub-endpoint`, `fix/rss-timezone`
|
|
|
|
**Alternative**: Simple description without prefix (e.g., `micropub-endpoint`)
|
|
|
|
### Tagging Strategy
|
|
|
|
**Format**: `vMAJOR.MINOR.PATCH[-PRERELEASE]`
|
|
|
|
**Type**: Annotated tags (always)
|
|
|
|
**Examples**:
|
|
- `v0.1.0` - Development release
|
|
- `v1.0.0` - First stable release
|
|
- `v1.0.1` - Patch release
|
|
- `v1.0.0-alpha.1` - Pre-release
|
|
|
|
**Tag message format**:
|
|
```
|
|
Release MAJOR.MINOR.PATCH: <Brief description>
|
|
|
|
[Optional details]
|
|
```
|
|
|
|
### Workflows
|
|
|
|
**Development (0.x.y)**:
|
|
1. Work on `main` or feature branches
|
|
2. Commit frequently
|
|
3. Tag development milestones (v0.1.0, v0.2.0)
|
|
4. Breaking changes allowed
|
|
|
|
**Stable releases (1.0.0+)**:
|
|
1. Prepare release on `main`
|
|
2. Update version and changelog
|
|
3. Commit version bump
|
|
4. Create annotated tag
|
|
5. Push main and tag
|
|
|
|
**Hotfixes (post-1.0.0)**:
|
|
1. Branch from release tag
|
|
2. Fix bug
|
|
3. Update version and changelog
|
|
4. Tag new patch version
|
|
5. Merge to `main`
|
|
6. Push main and tag
|
|
7. Delete hotfix branch
|
|
|
|
## Rationale
|
|
|
|
### Why Simplified Trunk-Based Development?
|
|
|
|
**Trunk-based development** means developers integrate to a single branch (`main`) frequently, using short-lived feature branches.
|
|
|
|
**Pros**:
|
|
1. **Simple** - One primary branch, minimal overhead
|
|
2. **Scalable** - Works for solo and small teams
|
|
3. **Fast integration** - Reduces merge conflicts
|
|
4. **Always releasable** - Main stays stable
|
|
5. **Aligns with CI/CD** - Easy to automate testing
|
|
6. **Reduces complexity** - No long-lived branches to manage
|
|
|
|
**Fits StarPunk because**:
|
|
- Personal project optimized for simplicity
|
|
- Small codebase, infrequent releases
|
|
- Solo developer initially
|
|
- No need for complex branching
|
|
|
|
### Why Main Instead of Master?
|
|
|
|
**Decision**: Use `main` as primary branch name
|
|
|
|
**Rationale**:
|
|
1. **Industry standard** - GitHub, GitLab default since 2020
|
|
2. **Inclusive language** - Removes potentially offensive terminology
|
|
3. **Aligns with modern practices** - Most new projects use `main`
|
|
4. **Clear semantics** - "Main" clearly indicates primary branch
|
|
5. **No functional difference** - Just a name, but better name
|
|
|
|
**Migration**:
|
|
- Project just renamed `master` → `main`
|
|
- All documentation uses `main` consistently
|
|
|
|
### Why Not Git Flow?
|
|
|
|
**Git Flow** is a popular branching model with `main`, `develop`, `release`, `hotfix`, and `feature` branches.
|
|
|
|
**Considered but rejected**:
|
|
|
|
**Pros**:
|
|
- Well-defined process
|
|
- Clear separation of development and production
|
|
- Structured release process
|
|
|
|
**Cons**:
|
|
- **Too complex** for indie project
|
|
- **Overhead** - Multiple long-lived branches
|
|
- **Slow integration** - Features merge to develop, not main
|
|
- **Designed for** scheduled releases, not continuous delivery
|
|
- **Overkill** for single developer
|
|
|
|
**Conclusion**: Git Flow's complexity doesn't justify benefits for StarPunk's scale
|
|
|
|
### Why Not GitHub Flow?
|
|
|
|
**GitHub Flow** is a simpler model: just `main` and feature branches, deploy from `main`.
|
|
|
|
**Very close to our choice**:
|
|
|
|
**Pros**:
|
|
- Simple - only `main` + feature branches
|
|
- Fast - deploy anytime
|
|
- Works well with pull requests
|
|
|
|
**Differences from our approach**:
|
|
- GitHub Flow deploys directly from `main`
|
|
- We tag releases on `main` instead
|
|
- We add hotfix branches for production patches
|
|
|
|
**Conclusion**: We essentially use GitHub Flow + semantic versioning + hotfix branches
|
|
|
|
### Why Annotated Tags?
|
|
|
|
**Annotated vs lightweight tags**:
|
|
|
|
**Annotated tags** (chosen):
|
|
- Contain metadata (tagger, date, message)
|
|
- Can include release notes
|
|
- Can be GPG signed
|
|
- Treated as full Git objects
|
|
- Required: `git tag -a v1.0.0 -m "Release 1.0.0"`
|
|
|
|
**Lightweight tags** (rejected):
|
|
- Just pointers to commits
|
|
- No metadata
|
|
- Created: `git tag v1.0.0`
|
|
|
|
**Decision**: Always use annotated tags for releases
|
|
- Provides complete release history
|
|
- Can include release notes in tag message
|
|
- Better for professional releases
|
|
|
|
### Why Feature Branches?
|
|
|
|
**Alternatives**:
|
|
1. **Direct commits to main** - Fast but risky
|
|
2. **Feature branches** - Slight overhead but safer
|
|
3. **Pull request workflow** - Most structured
|
|
|
|
**Decision**: Use feature branches with flexible merge approach
|
|
|
|
**For solo development**:
|
|
- Feature branches optional for small changes
|
|
- Required for larger features
|
|
- Merge directly without pull request
|
|
|
|
**For team development**:
|
|
- Feature branches required
|
|
- Pull request review before merge
|
|
- Delete branch after merge
|
|
|
|
**Benefits**:
|
|
- Isolates work in progress
|
|
- Enables experimentation
|
|
- Keeps main stable
|
|
- Scalable to team workflow
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
1. **Simple to understand** - One primary branch, clear workflows
|
|
2. **Scalable** - Works solo, scales to small teams
|
|
3. **Fast integration** - Short-lived branches reduce conflicts
|
|
4. **Clean history** - Clear tags for every release
|
|
5. **Semantic versioning alignment** - Tag strategy matches SemVer
|
|
6. **Hotfix capability** - Can patch production releases
|
|
7. **Low overhead** - No complex branch management
|
|
8. **Standard practices** - Uses modern Git conventions
|
|
9. **Well-documented** - Clear workflows for common scenarios
|
|
10. **Flexible** - Can use pull requests or direct merges
|
|
|
|
### Negative
|
|
|
|
1. **Discipline required** - Main must stay stable (tests must pass)
|
|
2. **Manual version management** - Must update version, changelog, tag (for V1)
|
|
3. **Solo optimization** - Strategy favors individual over large team
|
|
4. **No develop buffer** - Changes go directly to main (requires good testing)
|
|
|
|
### Neutral
|
|
|
|
1. **Feature branch discipline** - Must keep branches short-lived
|
|
2. **Test coverage important** - Main stability depends on testing
|
|
3. **Rebase vs merge** - Team must choose and be consistent
|
|
|
|
### Mitigations
|
|
|
|
**For main stability**:
|
|
- Run tests before merging
|
|
- Use pull requests for team development
|
|
- Establish branch protection rules when team grows
|
|
|
|
**For version management**:
|
|
- Document clear release process
|
|
- Create release checklist
|
|
- Consider automation in V2+ if needed
|
|
|
|
**For long-lived branches**:
|
|
- Review open branches weekly
|
|
- Delete stale branches
|
|
- Encourage frequent integration
|
|
|
|
## Implementation
|
|
|
|
### Immediate Actions
|
|
|
|
1. **Primary branch**: Already renamed to `main`
|
|
2. **Create documentation**: `docs/standards/git-branching-strategy.md`
|
|
3. **Update all references**: Ensure docs use `main` consistently
|
|
4. **Initial tag**: Tag current state as `v0.1.0`
|
|
|
|
### Branch Protection (Future)
|
|
|
|
When team grows or project matures, add GitHub branch protection:
|
|
|
|
```
|
|
Settings → Branches → Add rule for main:
|
|
- Require pull request reviews (1 approval)
|
|
- Require status checks to pass
|
|
- Prevent force push
|
|
- Prevent deletion
|
|
```
|
|
|
|
For solo development: Self-discipline instead of enforced rules
|
|
|
|
### Release Process
|
|
|
|
**Development releases (0.x.y)**:
|
|
1. Update `starpunk/__init__.py` version
|
|
2. Update `CHANGELOG.md`
|
|
3. Commit: `git commit -m "Bump version to 0.x.y"`
|
|
4. Tag: `git tag -a v0.x.y -m "Development release 0.x.y"`
|
|
5. Push: `git push origin main v0.x.y`
|
|
|
|
**Stable releases (1.0.0+)**:
|
|
1. Update version and changelog
|
|
2. Commit version bump
|
|
3. Tag: `git tag -a v1.0.0 -m "Release 1.0.0: First stable release"`
|
|
4. Push: `git push origin main v1.0.0`
|
|
|
|
**Hotfixes**:
|
|
1. Branch: `git checkout -b hotfix/1.0.1-fix v1.0.0`
|
|
2. Fix bug and update version
|
|
3. Tag: `git tag -a v1.0.1 -m "Hotfix 1.0.1: Bug fix"`
|
|
4. Merge: `git checkout main && git merge hotfix/1.0.1-fix`
|
|
5. Push: `git push origin main v1.0.1`
|
|
6. Delete: `git branch -d hotfix/1.0.1-fix`
|
|
|
|
### Documentation
|
|
|
|
Created comprehensive documentation:
|
|
- **Strategy document**: `docs/standards/git-branching-strategy.md`
|
|
- Branch types and naming
|
|
- Workflows and examples
|
|
- Best practices
|
|
- Troubleshooting
|
|
- **This ADR**: `docs/decisions/ADR-009-git-branching-strategy.md`
|
|
- Decision rationale
|
|
- Alternatives considered
|
|
|
|
## Alternatives Considered
|
|
|
|
### Alternative 1: Git Flow
|
|
|
|
**Description**: Use full Git Flow with `main`, `develop`, `release`, `hotfix`, `feature` branches
|
|
|
|
**Pros**:
|
|
- Well-established pattern
|
|
- Clear separation of development and production
|
|
- Structured release process
|
|
- Good for scheduled releases
|
|
|
|
**Cons**:
|
|
- Too complex for indie project
|
|
- Multiple long-lived branches
|
|
- Slower integration
|
|
- More overhead
|
|
- Designed for different release model
|
|
|
|
**Rejected**: Complexity doesn't match project scale
|
|
|
|
### Alternative 2: Trunk-Based Development (Pure)
|
|
|
|
**Description**: All commits directly to `main`, no feature branches
|
|
|
|
**Pros**:
|
|
- Maximum simplicity
|
|
- Fastest integration
|
|
- No branch management
|
|
|
|
**Cons**:
|
|
- Risky - broken commits go to main
|
|
- No isolation for work in progress
|
|
- Difficult for team collaboration
|
|
- No experimentation space
|
|
|
|
**Rejected**: Too risky, doesn't scale to team
|
|
|
|
### Alternative 3: GitHub Flow (Pure)
|
|
|
|
**Description**: `main` + feature branches, deploy from `main` continuously
|
|
|
|
**Pros**:
|
|
- Simple and well-documented
|
|
- Works well with pull requests
|
|
- Fast deployment
|
|
|
|
**Cons**:
|
|
- Designed for continuous deployment
|
|
- Doesn't emphasize versioned releases
|
|
- No hotfix branch pattern
|
|
|
|
**Partially adopted**: We use this + semantic versioning + hotfix branches
|
|
|
|
### Alternative 4: Release Branches Primary
|
|
|
|
**Description**: Always use release branches, never tag `main` directly
|
|
|
|
**Pros**:
|
|
- Clear release preparation phase
|
|
- Can stabilize release while main continues
|
|
|
|
**Cons**:
|
|
- Adds complexity
|
|
- Creates long-lived branches
|
|
- Overkill for small project
|
|
|
|
**Rejected**: Unnecessary complexity for V1
|
|
|
|
### Alternative 5: Keep Master Branch Name
|
|
|
|
**Description**: Continue using `master` instead of `main`
|
|
|
|
**Pros**:
|
|
- Traditional name
|
|
- No migration needed
|
|
- No functional difference
|
|
|
|
**Cons**:
|
|
- Outdated convention
|
|
- Out of step with industry
|
|
- Potentially offensive terminology
|
|
- New projects use `main`
|
|
|
|
**Rejected**: Modern standard is `main`, no reason not to adopt
|
|
|
|
## References
|
|
|
|
### Git Branching Models
|
|
|
|
- [Trunk-Based Development](https://trunkbaseddevelopment.com/) - Pattern we primarily follow
|
|
- [GitHub Flow](https://guides.github.com/introduction/flow/) - Simplified flow (close to ours)
|
|
- [Git Flow](https://nvie.com/posts/a-successful-git-branching-model/) - More complex model (not adopted)
|
|
- [GitLab Flow](https://docs.gitlab.com/ee/topics/gitlab_flow.html) - Hybrid approach
|
|
|
|
### Branch Naming
|
|
|
|
- [GitHub Renaming](https://github.com/github/renaming) - Main branch renaming initiative
|
|
- [Git Branch Naming](https://deepsource.io/blog/git-branch-naming-conventions/) - Naming conventions
|
|
|
|
### Versioning Integration
|
|
|
|
- [Semantic Versioning](https://semver.org/) - Version numbering
|
|
- [Git Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging) - Tag documentation
|
|
|
|
### Internal Documentation
|
|
|
|
- [ADR-008: Versioning Strategy](/home/phil/Projects/starpunk/docs/decisions/ADR-008-versioning-strategy.md) - Semantic versioning decision
|
|
- [Versioning Strategy](/home/phil/Projects/starpunk/docs/standards/versioning-strategy.md) - Complete versioning spec
|
|
- [Git Branching Strategy](/home/phil/Projects/starpunk/docs/standards/git-branching-strategy.md) - Complete branching spec
|
|
- [Development Setup](/home/phil/Projects/starpunk/docs/standards/development-setup.md) - Development workflow
|
|
|
|
---
|
|
|
|
**ADR**: 009
|
|
**Date**: 2025-11-18
|
|
**Status**: Accepted
|
|
**Decision**: Adopt simplified trunk-based development with `main` branch, feature branches, semantic versioning tags, and hotfix capability
|
|
**Supersedes**: None
|