Your Git workflow affects how fast you ship, how often you break things, and how much your team fights over merge conflicts. Choose wisely.
The Contenders
Git Flow
The traditional branching model with long-lived branches:
How it works:
mainalways reflects productiondevelopis the integration branch- Features branch from
develop, merge back todevelop - Releases branch from
develop, merge to bothmainanddevelop - Hotfixes branch from
main, merge to bothmainanddevelop
| |
Pros:
- Clear separation between development and production
- Parallel release preparation
- Good for versioned software (mobile apps, installable software)
Cons:
- Complex, many branches to manage
- Merge conflicts accumulate
- Slow to ship (features wait for releases)
GitHub Flow
Simplified: just main and feature branches.
How it works:
mainis always deployable- Create feature branches from
main - Open PR, get review, merge to
main - Deploy immediately after merge
| |
Pros:
- Simple, easy to understand
- Fast iteration (ship multiple times per day)
- Less merge conflict pain
Cons:
- Requires solid CI/CD and testing
- No staging in the workflow itself
- Harder for versioned releases
Trunk-Based Development
Even simpler: everyone commits to main (trunk).
How it works:
- Everyone commits to
main(directly or via very short-lived branches) - Branches live hours, not days
- Feature flags hide incomplete work
- Deploy continuously
| |
Pros:
- Minimal merge conflicts
- Fastest iteration
- Forces small, incremental changes
- Works great with feature flags
Cons:
- Requires discipline (small commits)
- Needs excellent CI/CD
- Feature flags add complexity
- Scary without good test coverage
GitLab Flow
Middle ground: environment branches.
Or with release branches:
How it works:
- Feature branches merge to
main maindeploys to staging automatically- Promote to production by merging
mainto production branch - Or: maintain stable branches for each release
How to Choose
Use Git Flow if:
- You ship versioned releases (v1.0, v2.0)
- Multiple versions need parallel support
- You have dedicated release managers
- Compliance requires formal release process
Use GitHub Flow if:
- You deploy continuously (SaaS, web apps)
- You have solid CI/CD
- Team is small to medium
- You want simplicity
Use Trunk-Based if:
- You deploy many times per day
- You have excellent test coverage
- Team is disciplined about small changes
- You’re comfortable with feature flags
Use GitLab Flow if:
- You need environment promotion (staging → prod)
- You want something between Git Flow and GitHub Flow
- You maintain multiple release versions
Branch Naming Conventions
Consistent naming helps automation and readability:
| |
Automate enforcement:
| |
Commit Message Standards
Use conventional commits for automated changelogs:
Enforce with commitlint:
| |
Pull Request Best Practices
Keep PRs Small
PR Template
| |
Review Checklist
Reviewers should check:
- Does the code do what it claims?
- Are there tests?
- Are edge cases handled?
- Is it readable?
- Any security concerns?
Merge Strategies
Merge Commit
| |
Preserves full history. Good for seeing what was in each feature.
Squash and Merge
| |
Clean history. One commit per feature. Loses individual commit detail.
Rebase and Merge
| |
Linear history. Rewrites commits. Can be confusing if not careful.
My recommendation: Squash for features, merge commit for releases.
Handling Conflicts
Prevention
- Small, frequent PRs
- Pull from main often
- Communicate about shared files
- Use code owners for critical paths
Resolution
| |
Quick Reference
| Workflow | Best For | Complexity | Deploy Speed |
|---|---|---|---|
| Git Flow | Versioned releases | High | Slow |
| GitHub Flow | Continuous deployment | Low | Fast |
| Trunk-Based | High-frequency deploys | Low | Fastest |
| GitLab Flow | Environment promotion | Medium | Medium |
The best workflow is one your team actually follows. Start simple, add complexity only when needed.