Git doesn’t enforce a workflow. You can branch however you want, merge whenever you want, push whatever you want. That freedom is powerful and dangerous.
A good branching strategy reduces merge conflicts, enables parallel development, and makes releases predictable. A bad one creates confusion, broken builds, and deployment fear.
Trunk-Based Development
The simplest model: everyone commits to main, frequently.
Rules:
- Features are small, completed in hours or a day
- All commits pass CI before merging
- Feature flags hide incomplete work
- No long-lived branches
| |
Pros: Simple, minimal merge conflicts, continuous integration Cons: Requires feature flags, demands CI discipline, scary without good tests
Best for: Small teams, experienced developers, strong CI/CD.
GitHub Flow
One step up: short-lived feature branches with PR review.
Rules:
- Main is always deployable
- Branch from main for features
- Open PR for discussion
- Merge after review and CI passes
- Deploy immediately after merge
| |
Pros: Simple, encourages review, works well with CI/CD Cons: No staging environment distinction, features must be complete to merge
Best for: SaaS products, web apps with continuous deployment.
GitFlow
Structured model with multiple long-lived branches:
Branches:
main: Production code, tagged releases onlydevelop: Integration branch for featuresfeature/*: Individual features, branch from developrelease/*: Release preparation, branch from develophotfix/*: Production fixes, branch from main
| |
Pros: Clear release process, parallel development, hotfix path Cons: Complex, merge overhead, not suited for continuous deployment
Best for: Packaged software, mobile apps, scheduled releases.
Release Branches
Simplified GitFlow for products with multiple supported versions:
| |
Best for: Libraries, APIs, products with LTS versions.
Commit Message Conventions
Consistent messages enable automation:
Types:
feat: New featurefix: Bug fixdocs: Documentationstyle: Formattingrefactor: Code restructuringtest: Testschore: Maintenance
| |
Tools like semantic-release use these to auto-generate changelogs and version bumps.
Merge vs Rebase vs Squash
Merge commit: Preserves full history
| |
Rebase: Linear history
| |
Squash: Single commit
| |
Recommendation: Squash for features (clean history), merge for releases (preserve context).
Branch Protection
Prevent accidents with branch rules:
| |
Nobody can push directly to main, not even admins in a hurry.
Handling Long-Running Branches
Sometimes branches must live longer. Minimize pain:
| |
Sync at least weekly. Daily is better. The longer you wait, the worse conflicts become.
Monorepo Considerations
Multiple projects in one repo need path-based triggers:
| |
Consider tools like Nx or Turborepo for smarter builds.
Choosing a Strategy
| Situation | Strategy |
|---|---|
| Small team, continuous deploy | Trunk-based |
| Standard SaaS product | GitHub Flow |
| Mobile app, scheduled releases | GitFlow |
| Library with versions | Release branches |
| Enterprise, compliance needs | GitFlow + approvals |
Start simple. Add complexity only when you feel specific pain.
Git workflows are about communication as much as code. A good strategy makes it obvious where work happens, how it gets reviewed, and when it ships.
Pick a model, document it, enforce it with tooling. The best workflow is the one your team actually follows.