๐ฟ Git Branching Strategies
Choosing the right branching strategy is crucial for team productivity. Different strategies suit different team sizes, release cycles, and project types.
GitFlow
Multiple long-lived branches for structured release management.
Best for: Versioned software, mobile apps
GitHub Flow
Simple workflow with main + feature branches.
Best for: SaaS, web apps, startups
Trunk-Based
Everyone commits to main with short-lived branches.
Best for: Large teams, continuous deployment
GitLab Flow
Environment branches for staged deployments.
Best for: Multi-environment, enterprise
๐ GitFlow
GitFlow uses multiple long-lived branches for structured release management.
Branch Structure
main โ Production-ready code only develop โ Integration branch for features feature/* โ New features (branch from develop) release/* โ Prepare for release (branch from develop) hotfix/* โ Emergency fixes (branch from main)
Visual Flow
main โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ
โ v2.0 โฒ v2.1 โฒ v2.2
โ โ โ
hotfix โ โโโโโโโโโโ โ
โ โ โ
โผ โผ โ
develop โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ
โ โฒ โ โฒ โฒ
โ โ โ โ โ
feature โโโโโโโ โโโโโโโ โ
โ โฒ โ
release โโโโโโโโโโโโโโโโโโโโ
Pros & Cons
| โ Pros | โ Cons |
|---|---|
| Clear separation of concerns | Complex, many branches |
| Parallel development | Long-lived branches = merge conflicts |
| Structured release process | Slow release cycles |
| Good for versioned software | Overkill for continuous deployment |
| Supports multiple versions | Steep learning curve |
๐ GitHub Flow
A simplified workflow focused on continuous deployment.
Visual Flow
main โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ
โ โฒ โ โฒ โ โฒ
โ โ โ โ โ โ
feature โโโโโโ โโโโโโ โโโโโโ
WORKFLOW:
1. Create branch from main
2. Make changes, commit
3. Open Pull Request
4. Review & discuss
5. Deploy and test
6. Merge to main
Pros & Cons
| โ Pros | โ Cons |
|---|---|
| Simple, easy to understand | No separate develop branch |
| Fast deployment | Requires robust CI/CD |
| Continuous deployment friendly | Main must always be deployable |
| Quick feedback loop | Less structure for complex releases |
| Minimal branch management | No version support |
๐ Trunk-Based Development
Everyone commits to a single branch (trunk/main) with very short-lived feature branches.
Visual Flow
main โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถ
(trunk) โฒ โฒ โฒ โฒ โฒ โฒ โฒ โฒ โฒ โฒ โฒ โฒ โฒ
โ โ โ โ โ โ โ โ โ โ โ โ โ
โ โ โ โ โ โ โ โ โ โ โ โ โ
Short-lived branches (< 24 hours)
Key Principles
๐ Commit Frequently
Multiple times per day to trunk. Small, incremental changes.
โฑ๏ธ Short-Lived Branches
Feature branches live less than 1 day. Merge quickly.
๐ฉ Feature Flags
Hide incomplete features behind flags. Enable gradually.
๐งช Comprehensive Testing
Automated tests catch issues immediately.
Feature Flags Example
// Feature flag controls visibility
if (featureFlags.newCheckout) {
return <NewCheckout />; // New feature (hidden)
}
return <OldCheckout />; // Current production
// Gradual rollout: 1% โ 10% โ 50% โ 100%
// Bug found? Disable flag instantly (no rollback needed)
Pros & Cons
| โ Pros | โ Cons |
|---|---|
| Minimal merge conflicts | Requires mature CI/CD |
| Fastest feedback loop | Needs feature flags infrastructure |
| Continuous integration | Requires high test coverage |
| No branch management overhead | Steep learning curve |
| Proven at scale (Google, Meta) | Not suitable for all teams |
๐ข Real-World Scenarios
When does each strategy work best? Let's look at concrete examples.
Mobile Banking App โ GitFlow
Traditional bank releasing mobile app
- Scheduled releases with version numbers (v2.1, v2.2)
- Long QA cycles before release
- Hotfix capability for production emergencies
- Release branch allows "feature freeze" for testing
- GitHub Flow: Can't do 2-month QA cycles, no version support
- Trunk-Based: Regulators need to approve releases
SaaS Web Dashboard โ GitHub Flow
Startup building analytics dashboard
- Simple workflow, minimal overhead
- Deploy immediately when ready
- Bug found? Fix, PR, merge, deployed in hours
- No version numbers needed (it's a website!)
- GitFlow: Overkill for a simple web app, slows deployment
- Trunk-Based: Adds complexity team doesn't need yet
Google-Scale Monorepo โ Trunk-Based
Tech giant with thousands of engineers
- Long-lived branches at this scale = merge conflict nightmare
- Everyone commits to trunk = always integrated
- Feature flags control visibility
- Automated testing catches issues immediately
- GitFlow: 5000 developers with long-lived branches = constant conflicts
- GitHub Flow: Multi-day branches cause integration pain at scale
What Top Companies Use
๐งน Keeping Git History Clean
A clean Git history makes debugging easier, code review faster, and project maintenance simpler.
Why Clean History Matters
๐ Debugging
git bisect works better on linear history to find bug-introducing commits.
๐ Code Review
Reviewers see logical, focused commits instead of noise.
๐ Documentation
History tells the story of the project.
โฉ๏ธ Reverts
Can revert single commits cleanly without side effects.
Messy vs Clean History
โ MESSY HISTORY (Without Rebase) * e5f6g7h Merge branch 'feature-B' |\ | * a1b2c3d Add feature B part 3 | * d4e5f6g Add feature B part 2 * | h7i8j9k Merge branch 'feature-A' |\ \ | * | l0m1n2o Add feature A part 2 | * | p3q4r5s Add feature A part 1 | |/ * | t6u7v8w Fix typo in readme |/ * b2c3d4e Initial commit ๐ Hard to follow! Multiple merge commits, crossing lines... โ CLEAN HISTORY (With Rebase) * e5f6g7h Add feature B part 3 * a1b2c3d Add feature B part 2 * d4e5f6g Add feature B part 1 * h7i8j9k Add feature A part 2 * l0m1n2o Add feature A part 1 * p3q4r5s Fix typo in readme * b2c3d4e Initial commit ๐ Linear, easy to read, tells a clear story!
Tools for Clean History
| Tool | Purpose |
|---|---|
git rebase | Move commits to new base, linearize history |
git rebase -i | Edit, squash, reorder, drop commits |
git commit --amend | Fix the last commit |
git reset | Undo commits (various modes) |
๐ Rebase in Detail
Rebase means "re-apply your commits on top of another branch" - moving your branch to start from a different point.
Merge vs Rebase
BEFORE (Divergent History):
CโโโDโโโE (feature)
/
AโโโBโโโFโโโG (main)
AFTER MERGE:
CโโโDโโโEโโโM (feature)
/ /
AโโโBโโโFโโโGโโโโ (main)
โ
Merge commit (creates extra commit)
AFTER REBASE:
AโโโBโโโFโโโGโโโC'โโโD'โโโE' (feature)
โ
main
Your commits replayed on top of main (linear!)
How Rebase Works Step-by-Step
- Git identifies common ancestor (B)
- Git saves your commits (C, D, E) temporarily
- Git moves feature to new base (G)
- Git replays each commit one by one:
- Replay C on G โ C'
- Replay D on C' โ D'
- Replay E on D' โ E'
Rebase Commands
# Rebase current branch onto main
git rebase main
# Rebase with remote tracking branch
git fetch origin
git rebase origin/main
# Continue after resolving conflicts
git rebase --continue
# Abort rebase (go back to before)
git rebase --abort
# Skip problematic commit
git rebase --skip
The Golden Rule
Rebase rewrites history. If others have your old commits, they'll have conflicts!
| โ Safe to Rebase | โ Don't Rebase |
|---|---|
| Your local commits (not pushed) | Shared branches (main, develop) |
| Your feature branch (only you working) | Branches others have pulled |
| Before creating Pull Request | After others are building on your commits |
Force Push After Rebase
# After rebasing a pushed branch, you must force push
git push --force-with-lease
# --force-with-lease is SAFER than --force
# It fails if remote has new commits you haven't seen
# Protects against overwriting teammate's work
๐ฆ Interactive Rebase & Squashing
Interactive rebase lets you edit, reorder, squash, or drop commits before sharing.
# Interactive rebase last 4 commits
git rebase -i HEAD~4
# Interactive rebase all commits since branching from main
git rebase -i main
Interactive Rebase Options
| Command | Action |
|---|---|
pick | Use commit as-is |
reword | Use commit, but edit the message |
edit | Use commit, but stop for amending |
squash | Meld into previous commit (keep message) |
fixup | Meld into previous commit (discard message) |
drop | Remove commit entirely |
Example: Cleaning Up Before PR
BEFORE (messy commits): * jkl3456 Add validation * ghi9012 WIP: debugging * def5678 Fix typo * abc1234 Add login form RUN: git rebase -i HEAD~4 Edit the file: โโโโโโโโโโโโโโโโโโโโโโโโ pick abc1234 Add login form fixup def5678 Fix typo โ merge into above drop ghi9012 WIP: debugging โ delete this squash jkl3456 Add validation โ merge with message โโโโโโโโโโโโโโโโโโโโโโโโ AFTER (clean history): * xyz9999 Add login form with validation (One clean, logical commit!)
Squash Merge in GitHub/GitLab
Many teams use "Squash and Merge" when merging PRs:
โ Pros
- Main branch has clean, logical commits
- Each PR = one commit
- Easy to revert entire features
โ Cons
- Loses granular commit history
- Can't cherry-pick individual changes later
๐ Conventional Commits
A specification for adding human and machine-readable meaning to commit messages.
Format
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
Types
| Type | Description |
|---|---|
feat | New feature |
fix | Bug fix |
docs | Documentation only |
style | Formatting, no code change |
refactor | Code restructuring |
test | Adding/fixing tests |
chore | Maintenance tasks |
perf | Performance improvement |
Examples
# Feature
feat(auth): add OAuth2 login support
# Bug fix
fix(api): handle null response from server
# Documentation
docs(readme): update installation instructions
# Breaking change (note the !)
feat(api)!: change response format to JSON
BREAKING CHANGE: response is now JSON instead of XML
โ Best Practices
๐ Commits
- โ Write meaningful commit messages
- โ Commit early, commit often
- โ One logical change per commit
- โ Use conventional commits format
- โ Don't commit broken code
- โ Don't use vague messages
๐ฟ Branches
- โ Use descriptive names (feature/add-login)
- โ Keep branches short-lived
- โ Delete merged branches
- โ Pull from main frequently
- โ Don't let branches get stale
- โ Don't work directly on main
๐ Pull Requests
- โ Keep PRs small and focused
- โ Write good PR descriptions
- โ Request reviews early
- โ Address comments promptly
- โ Don't create huge PRs (1000+ lines)
- โ Don't mix features in one PR
๐ History
- โ Rebase before sharing
- โ Use merge for integrating to main
- โ Squash WIP commits before PR
- โ Don't rewrite shared history
- โ Don't force push to main
- โ Don't keep "WIP" commits in main
๐ฏ Strategy Selection Guide
Quick Decision Guide
Do you have scheduled releases with version numbers? โโโ YES โ Do you need to support multiple versions? โ โโโ YES โ GitFlow โ โโโ NO โ GitLab Flow โ โโโ NO โ How often do you deploy? โโโ Daily or more โ Team size? โ โโโ < 50 โ GitHub Flow โ โโโ > 50 โ Trunk-Based โ โโโ Weekly/Monthly โ GitLab Flow Do you have external contributors? โโโ YES โ Forking Workflow (+ internal strategy) โโโ NO โ Use internal strategy only
Quick Reference
| Scenario | Best Strategy |
|---|---|
| Mobile app with App Store releases | GitFlow |
| SaaS web application | GitHub Flow |
| Large team (50+ developers) | Trunk-Based |
| Multiple deployment environments | GitLab Flow |
| Open source with external contributors | Forking |
| Startup, small team, fast iteration | GitHub Flow |
| Enterprise with compliance | GitFlow / GitLab Flow |
| Monorepo at scale | Trunk-Based |
๐ Summary
1. Choose Right Strategy
Based on team size, release cycle, and project type.
2. Keep History Clean
Use rebase, squash, and interactive rebase.
3. Follow Conventions
Consistent commit messages and branch names.
4. Rebase Safely
Only on commits that haven't been shared.