Branch Strategy
Branch Naming Conventions
Every branch name must follow a structured prefix convention. This keeps the repository navigable, enables CI/CD automation, and makes intent immediately clear.
Required Prefixes
| Prefix | Purpose | Example |
|---|---|---|
feature/ | New functionality or capability | feature/user-avatar-upload |
fix/ | Bug fixes for existing behavior | fix/login-redirect-loop |
hotfix/ | Urgent production fixes | hotfix/payment-null-pointer |
release/ | Release preparation and stabilization | release/2.4.0 |
chore/ | Maintenance, dependencies, tooling | chore/upgrade-eslint-9 |
docs/ | Documentation-only changes | docs/api-authentication-guide |
refactor/ | Code restructuring without behavior change | refactor/extract-billing-service |
test/ | Adding or fixing tests only | test/payment-edge-cases |
experiment/ | Exploratory work, not intended for merge | experiment/graphql-federation |
Naming Rules
- •Use lowercase with hyphens as separators:
feature/add-user-searchnotfeature/Add_User_Search - •Keep names concise but descriptive:
fix/cart-totalnotfix/the-bug-where-cart-total-shows-wrong-amount - •Include a ticket or issue number when one exists:
feature/PROJ-1234-user-avatar-upload - •Never use personal names:
feature/search-apinotfeature/anthonys-search-work - •Avoid generic names:
fix/login-redirect-loopnotfix/bugorfix/stuff - •Maximum length: aim for under 50 characters after the prefix
Ticket Number Placement
When integrating with issue trackers, place the ticket number immediately after the prefix:
feature/PROJ-1234-user-avatar-upload fix/GH-567-null-pointer-on-empty-cart hotfix/INC-89-payment-gateway-timeout
This enables automated linking between branches, PRs, and issues.
Branching Models
Trunk-Based Development
The simplest model. All developers work on short-lived branches off main and merge back frequently.
main ─────●─────●─────●─────●─────●─────●─────
\ / \ / \ /
●─● ●─● ●
(feature) (fix) (feature)
When to Use Trunk-Based Development:
- •Teams with strong CI/CD pipelines and automated testing
- •Continuous deployment environments
- •Small to medium teams (2-15 developers)
- •Products that ship continuously (SaaS, web applications)
- •Teams practicing feature flags for incomplete work
Rules:
- •Branches live no longer than 1-2 days
- •Every commit to
mainmust pass all tests - •Use feature flags to hide incomplete functionality
- •No long-lived branches except
main - •Deploy from
mainon every merge (or at minimum daily) - •Keep changes small and incremental
Branch Lifecycle:
# Create branch from main git checkout main && git pull git checkout -b feature/PROJ-123-add-search # Work in small increments, commit frequently git add -p && git commit -m "Add search index configuration" git add -p && git commit -m "Implement basic search query endpoint" # Rebase onto main before merging git fetch origin && git rebase origin/main # Merge via PR (squash or merge commit per team convention) # Delete branch immediately after merge
Git Flow
A structured model with multiple long-lived branches for teams that need formal release management.
main ─────●──────────────────●──────────────
| |
develop ─────●────●────●────●───●────●─────────
\ / \ / | /
feature ●● ●● release ●
\ /
●─●
When to Use Git Flow:
- •Products with scheduled releases (mobile apps, installed software)
- •Teams that maintain multiple versions simultaneously
- •Regulated industries requiring release audit trails
- •Larger teams (15+ developers) needing coordination
- •Projects with dedicated QA phases
Branch Structure:
| Branch | Lifetime | Merges Into | Purpose |
|---|---|---|---|
main | Permanent | -- | Production-ready code, tagged releases |
develop | Permanent | main (via release) | Integration branch for features |
feature/* | Temporary | develop | New work in progress |
release/* | Temporary | main and develop | Release stabilization |
hotfix/* | Temporary | main and develop | Urgent production fixes |
Release Workflow:
# 1. Create release branch from develop git checkout develop && git pull git checkout -b release/2.4.0 # 2. Only bug fixes, documentation, and release prep on this branch # No new features allowed # 3. When stable, merge to main and tag git checkout main && git merge --no-ff release/2.4.0 git tag -a v2.4.0 -m "Release 2.4.0" # 4. Back-merge to develop git checkout develop && git merge --no-ff release/2.4.0 # 5. Delete release branch git branch -d release/2.4.0
Hotfix Workflow:
# 1. Branch from main git checkout main && git pull git checkout -b hotfix/payment-null-pointer # 2. Fix the issue, commit # 3. Merge to both main and develop git checkout main && git merge --no-ff hotfix/payment-null-pointer git tag -a v2.4.1 -m "Hotfix: payment null pointer" git checkout develop && git merge --no-ff hotfix/payment-null-pointer # 4. Delete hotfix branch git branch -d hotfix/payment-null-pointer
GitHub Flow
A simplified model that sits between trunk-based and Git Flow.
When to Use GitHub Flow:
- •Web applications with continuous deployment
- •Open source projects
- •Teams that want simplicity but still use pull requests
- •When Git Flow feels too heavy but you want PR-based review
Rules:
- •
mainis always deployable - •Branch from
mainfor any work - •Open a PR when you want feedback or are ready to merge
- •Merge to
mainafter review and CI passes - •Deploy immediately after merge
Branch Protection Rules
Recommended Protection for main
branch_protection:
main:
required_reviews: 1 # At least one approval
dismiss_stale_reviews: true # Re-review after new pushes
require_status_checks: true # CI must pass
required_checks:
- build
- test
- lint
restrict_pushes: true # No direct pushes
require_linear_history: true # Squash or rebase only
include_administrators: true # Rules apply to everyone
Protection by Branch Type
| Rule | main | develop | release/* | feature/* |
|---|---|---|---|---|
| Require PR | Yes | Yes | Yes | No |
| Required reviewers | 1-2 | 1 | 1-2 | 0 |
| Require CI pass | Yes | Yes | Yes | Optional |
| Allow force push | No | No | No | Yes (owner) |
| Allow deletion | No | No | After merge | Yes |
| Require signed commits | Recommended | Optional | Optional | No |
Release Tagging and Semantic Versioning
Semver Format
MAJOR.MINOR.PATCH | | | | | └── Bug fixes, no API changes | └──────── New features, backward compatible └────────────── Breaking changes
When to Bump Each Number
MAJOR (breaking): Removing an API endpoint. Changing a response format. Renaming a public function. Dropping support for a platform.
MINOR (feature): Adding a new endpoint. Adding optional parameters. New configuration options. New UI features.
PATCH (fix): Bug fixes. Security patches. Performance improvements. Documentation corrections.
Pre-release and Build Metadata
2.4.0-alpha.1 # Alpha pre-release 2.4.0-beta.2 # Beta pre-release 2.4.0-rc.1 # Release candidate 2.4.0+build.1234 # Build metadata (ignored in precedence)
Tagging Checklist
Before creating a release tag:
- • All tests pass on the release branch or main
- • CHANGELOG has been updated with all changes since last release
- • Version numbers updated in package files (package.json, pyproject.toml, etc.)
- • Migration scripts tested if applicable
- • Release notes drafted with user-facing summary
- • Breaking changes documented with migration guide
- • Dependencies audited for known vulnerabilities
Creating Tags
# Annotated tag (preferred for releases) git tag -a v2.4.0 -m "Release 2.4.0: Add user search, fix cart totals" # Push tags to remote git push origin v2.4.0 # Or push all tags git push origin --tags
Tag Naming Convention
- •Always prefix with
v:v2.4.0not2.4.0 - •Match the version in your package files exactly
- •Use annotated tags (not lightweight) for releases
Feature Branch Lifecycle
Standard Lifecycle
1. CREATE ── Branch from main/develop with proper prefix 2. DEVELOP ── Commit regularly, push daily 3. SYNC ── Rebase/merge from upstream regularly 4. REVIEW ── Open PR, request review 5. REVISE ── Address feedback, push updates 6. MERGE ── Squash or merge commit per convention 7. CLEANUP ── Delete branch locally and remotely
Keeping Branches Current
# Option A: Rebase (cleaner history, use for personal branches) git fetch origin git rebase origin/main # Option B: Merge (preserves history, use for shared branches) git fetch origin git merge origin/main
Stale Branch Policy
- •Branches with no commits for 14+ days should be reviewed
- •Branches with no commits for 30+ days should be closed or archived
- •Automate stale branch notifications via CI/CD
Decision Guide
Use this flowchart to choose your branching model:
Do you deploy continuously to production?
├── Yes: Do you need PR-based code review?
│ ├── Yes ──► GitHub Flow
│ └── No ──► Trunk-Based Development
└── No: Do you maintain multiple release versions?
├── Yes ──► Git Flow
└── No: Do you have scheduled release cycles?
├── Yes ──► Git Flow (simplified)
└── No ──► GitHub Flow
Anti-Patterns to Avoid
- •Long-lived feature branches -- Branches open for weeks accumulate merge conflicts and drift from main. Break work into smaller increments.
- •Merging main into feature branches repeatedly -- Creates a tangled history. Prefer rebasing for personal branches.
- •Skipping branch protection -- Even solo developers benefit from CI checks on main.
- •Inconsistent naming -- Mixed conventions make automation impossible. Enforce via CI hooks.
- •Forgetting to delete merged branches -- Stale branches clutter the repository. Configure auto-delete on merge.
- •Direct commits to main -- Bypasses review and CI. Always use PRs except for truly trivial changes on solo projects.
- •Release branches without version bumps -- Every release branch must update version numbers as its first commit.
- •Cherry-picking without tracking -- If you cherry-pick a fix to multiple branches, document which branches received the fix.