DEV Community

InstaDevOps
InstaDevOps

Posted on • Originally published at instadevops.com

Git Branching Strategies: Trunk-Based vs GitFlow vs GitHub Flow

Introduction

Your Git branching strategy directly impacts how fast you ship code, how often deployments break, and how much time your team wastes on merge conflicts. Yet most teams pick a branching model once and never revisit it, even as their team size, deployment frequency, and product complexity change.

In this guide, we will compare the three most popular branching strategies - trunk-based development, GitFlow, and GitHub Flow - with honest assessments of when each works and when each falls apart. We will also cover feature flags, release management, and monorepo-specific considerations that most branching guides skip entirely.

Trunk-Based Development

Trunk-based development (TBD) means everyone commits to a single branch (main/trunk), either directly or through very short-lived feature branches that last no more than a day or two. Google, Meta, and Netflix all practice trunk-based development at massive scale.

The core rules are simple:

  • The main branch is always deployable
  • Feature branches live less than 24-48 hours
  • Broken code is hidden behind feature flags, not long-lived branches
  • CI runs on every commit and blocks merges on failure

Here is a typical workflow:

# Start work
git checkout main
git pull origin main
git checkout -b feature/add-retry-logic

# Work for a few hours, then push
git add -A
git commit -m "Add exponential backoff to API client"
git push origin feature/add-retry-logic

# Open PR, get review, merge same day
# Delete branch immediately after merge
Enter fullscreen mode Exit fullscreen mode

When it works: Teams with strong CI/CD pipelines, good test coverage (70%+ meaningful coverage), and engineers comfortable with feature flags. Ideal for continuous deployment where you ship multiple times per day.

When it breaks down: Teams without automated testing, regulated industries requiring formal release sign-off, or junior-heavy teams where code review bottlenecks cause branches to pile up.

The biggest misconception about trunk-based development is that it means no code review. You absolutely still review code - you just review smaller, more frequent changes rather than massive PRs that touch 50 files.

GitFlow

GitFlow uses long-lived branches to manage releases: main holds production code, develop holds the next release, feature/* branches come off develop, release/* branches stabilize a release, and hotfix/* branches patch production emergencies.

main ─────────────────────────────────────────────
  │                               ▲          ▲
  │                               │          │
  └──▶ develop ──────────────────────────────────
         │         ▲       │            ▲
         │         │       │            │
         └── feature/x ──┘  └── feature/y ──┘
Enter fullscreen mode Exit fullscreen mode

A typical GitFlow release cycle:

# Start a feature
git checkout develop
git checkout -b feature/new-dashboard

# ... work for days/weeks ...

# Merge back to develop
git checkout develop
git merge --no-ff feature/new-dashboard

# Cut a release
git checkout -b release/2.4.0 develop

# Stabilize (bug fixes only)
git commit -m "Fix date formatting in dashboard"

# Finalize release
git checkout main
git merge --no-ff release/2.4.0
git tag -a v2.4.0 -m "Release 2.4.0"
git checkout develop
git merge --no-ff release/2.4.0
Enter fullscreen mode Exit fullscreen mode

When it works: Teams shipping versioned software (desktop apps, mobile apps, SDKs, on-prem installations), teams with scheduled release cycles (bi-weekly, monthly), and teams that need to maintain multiple release versions simultaneously.

When it breaks down: Web applications deploying continuously, small teams (under 5 engineers) where the overhead is not justified, and teams that end up with feature branches living for weeks, creating merge hell.

The honest truth about GitFlow in 2026: it was designed for a world where shipping software meant burning a CD. If you deploy a web application, GitFlow is almost certainly more process than you need.

GitHub Flow

GitHub Flow is the middle ground. You have one long-lived branch (main), create feature branches off it, open pull requests, and merge back to main after review. Main is always deployable.

# Create feature branch from main
git checkout main
git pull origin main
git checkout -b add-health-check-endpoint

# Work, commit, push
git add src/health.ts
git commit -m "Add /health endpoint with dependency checks"
git push origin add-health-check-endpoint

# Open PR on GitHub
gh pr create --title "Add health check endpoint" \
  --body "Adds /health endpoint that checks DB and Redis connectivity"

# After review and CI passes, merge via GitHub UI
# Deploy automatically from main
Enter fullscreen mode Exit fullscreen mode

When it works: Most web application teams. It is simple enough for small teams, scales well to medium teams (5-30 engineers), and pairs naturally with CI/CD pipelines that deploy on every merge to main.

When it breaks down: When feature branches live too long (the same problem as GitFlow but less structured), or when you need to maintain multiple production versions.

Feature Flags as a Branching Strategy

Feature flags are not a replacement for branching - they are a complement that makes trunk-based development and GitHub Flow viable for complex features that take weeks to build.

Here is a practical implementation using environment variables for simple flags and a feature flag service for anything more complex:

# Simple approach: environment-based flags
# docker-compose.yml
services:
  api:
    environment:
      - FEATURE_NEW_BILLING=false
      - FEATURE_V2_SEARCH=true
Enter fullscreen mode Exit fullscreen mode
// Application code
function getSearchResults(query) {
  if (process.env.FEATURE_V2_SEARCH === 'true') {
    return searchV2(query);  // New implementation
  }
  return searchV1(query);    // Existing implementation
}
Enter fullscreen mode Exit fullscreen mode

For production systems, use a proper feature flag service (LaunchDarkly, Unleash, Flagsmith, or even a simple Redis-backed solution):

// Using Unleash (open source)
const { initialize } = require('unleash-client');

const unleash = initialize({
  url: 'https://unleash.yourcompany.com/api',
  appName: 'api-service',
  customHeaders: { Authorization: process.env.UNLEASH_TOKEN },
});

app.get('/api/dashboard', async (req, res) => {
  if (unleash.isEnabled('new-dashboard', { userId: req.user.id })) {
    return res.json(await getNewDashboard(req.user));
  }
  return res.json(await getLegacyDashboard(req.user));
});
Enter fullscreen mode Exit fullscreen mode

The critical rule with feature flags: clean them up. Every flag should have an expiration date. Dead flags are technical debt that makes code harder to reason about. Set a calendar reminder to remove each flag within 2 weeks of full rollout.

Release Management Patterns

Regardless of your branching strategy, you need a release management approach. Here are three patterns ranked by deployment frequency:

Pattern 1: Continuous Deployment (trunk-based or GitHub Flow)

Every merge to main deploys to production automatically. Requires:

  • Full automated tests
  • Feature flags for incomplete work
  • Canary or blue-green deployments
  • Fast rollback capability
# GitHub Actions - deploy on every merge to main
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test
      - run: npm run build
      - name: Deploy to production
        run: |
          aws ecs update-service \
            --cluster production \
            --service api \
            --force-new-deployment
Enter fullscreen mode Exit fullscreen mode

Pattern 2: Release Trains (GitHub Flow with scheduled deploys)

Merge to main anytime, but deploy on a schedule (daily, twice a week). Good for teams building confidence in their pipeline.

Pattern 3: Versioned Releases (GitFlow)

Cut release branches, stabilize, tag, and deploy. Necessary for software with multiple live versions.

Monorepo Branching Considerations

Monorepos add complexity to any branching strategy because a single branch may contain changes to multiple services. Key considerations:

monorepo/
├── services/
│   ├── api/
│   ├── worker/
│   └── frontend/
├── packages/
│   ├── shared-types/
│   └── utils/
└── infrastructure/
    ├── terraform/
    └── k8s/
Enter fullscreen mode Exit fullscreen mode

Use path-based CI triggers so changes to one service do not trigger builds for unrelated services:

# GitHub Actions with path filters
name: API CI
on:
  pull_request:
    paths:
      - 'services/api/**'
      - 'packages/shared-types/**'
      - 'packages/utils/**'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd services/api && npm ci && npm test
Enter fullscreen mode Exit fullscreen mode

For monorepos, trunk-based development or GitHub Flow works far better than GitFlow. Long-lived feature branches in a monorepo are a recipe for merge conflicts across service boundaries.

Choosing the Right Strategy for Your Team

Here is a decision framework:

Factor Trunk-Based GitHub Flow GitFlow
Team size Any 2-30 5-50+
Deploy frequency Multiple/day Daily-weekly Weekly-monthly
Test coverage High (required) Medium-high Any
Feature flag maturity High Low-medium Not needed
Multiple live versions No No Yes
Regulatory requirements Works with flags Works fine Natural fit

For most startups and SMBs deploying web applications: Start with GitHub Flow. It has the lowest overhead and the fewest ways to shoot yourself in the foot. Move to trunk-based development when your CI/CD pipeline and test coverage are mature enough to support it.

Avoid GitFlow unless you are shipping versioned software (mobile apps, SDKs, on-prem products) or you have regulatory requirements that demand formal release branches.

Need Help with Your DevOps?

Setting up the right branching strategy, CI/CD pipeline, and deployment workflow is just the beginning. At InstaDevOps, we help startups and SMBs build production-grade DevOps infrastructure at a fraction of the cost of a full-time hire - starting at $2,999/mo.

Book a free 15-minute consultation to discuss your team's workflow and deployment challenges.

Top comments (0)