GitHub Flow: Simple Branching for Continuous Delivery

Learn GitHub Flow — the lightweight branching strategy built for continuous deployment. Covers feature branches, pull requests, and production deployment on every merge.

published: reading time: 12 min read updated: March 31, 2026

GitHub Flow: Simple Branching for Continuous Delivery

GitHub Flow is a response to the complexity of Git Flow. Where Git Flow defines five branch types with specific lifecycles, GitHub Flow has exactly one rule: everything starts from main, and everything merges back to main.

Created by GitHub as their internal workflow, this model assumes you can deploy from main at any time. There are no release branches, no version branches, no staging branches. If your code passes tests on a feature branch, it merges to main and deploys.

This post explores why some of the fastest-moving teams in the world use this model, where it breaks down, and how to implement it without shooting yourself in the foot.

When to Use / When Not to Use

Use GitHub Flow When

  • Continuous deployment — You deploy to production multiple times per day or week
  • Web applications and SaaS — No packaging, signing, or app store approval process
  • Small to medium teams — Where communication overhead of complex branching outweighs benefits
  • Feature flag culture — You control feature rollout with flags, not branch timing
  • Automated testing — Your CI pipeline catches regressions before they reach main

Do Not Use GitHub Flow When

  • Scheduled releases — You ship on a calendar cadence with QA gates
  • Multiple supported versions — You need to patch v1.x while developing v2.x
  • Regulated environments — You need formal change management and release documentation
  • No CI/CD pipeline — Without automated testing, every merge to main is a gamble
  • Mobile or desktop apps — Where each release requires a build and distribution process

Core Concepts

GitHub Flow has exactly three concepts:

ConceptDescription
main branchAlways deployable. The single source of truth.
Feature branchesBranch from main, merge back to main via pull request
Pull requestsCode review, discussion, and CI validation before merge

That’s it. No release branches. No develop branch. No version branches. The simplicity is the entire point.


graph LR
    A[main - Always Deployable] --> B[feature/new-ui]
    A --> C[feature/api-v2]
    A --> D[feature/bugfix]
    B -->|PR + CI| A
    C -->|PR + CI| A
    D -->|PR + CI| A
    A --> E[Deploy to Production]

Architecture and Flow Diagram

The complete GitHub Flow lifecycle from branch creation through production deployment:


graph TD
    A[main - Production] -->|create branch| B[feature/branch]
    B -->|commit| B
    B -->|push| C[Remote Feature Branch]
    C -->|open PR| D[Pull Request]
    D -->|code review| E[Review Feedback]
    E -->|update| C
    D -->|CI passes| F[Approved]
    F -->|merge| A
    A -->|auto deploy| G[Production]

Step-by-Step Guide

1. Create a Feature Branch

Always branch from the latest main:


# Ensure you have the latest main
git checkout main
git pull origin main

# Create and switch to your feature branch
git checkout -b feature/add-user-profile

Branch naming conventions matter for traceability:


# Good: descriptive with ticket reference
feature/PROJ-123-add-user-profile
feature/add-dark-mode
bugfix/fix-login-timeout

# Bad: vague or personal
feature/work-in-progress
johns-branch
temp-fix

2. Commit and Push Frequently

Small, focused commits make code review easier and bisect more effective:


# Make changes
git add src/components/UserProfile.tsx
git commit -m "feat: add user profile component skeleton"

git add src/styles/profile.css
git commit -m "feat: style user profile card"

# Push to remote
git push -u origin feature/add-user-profile

3. Open a Pull Request

The pull request is the heart of GitHub Flow. It’s where code review, automated testing, and team discussion converge:


# Using GitHub CLI
gh pr create \
  --base main \
  --head feature/add-user-profile \
  --title "feat: add user profile page" \
  --body "## Summary
Adds user profile page with avatar, bio, and settings link.

## Testing

- Manual: /profile endpoint renders correctly
- Unit: UserProfile component tests pass
- E2E: Profile navigation flow verified

## Screenshots

[Attach screenshots if UI changes]"

4. Review and Iterate

Code review is mandatory in GitHub Flow — it’s the only quality gate before main:

  • At least one approved review required
  • All CI checks must pass (tests, linting, type checking)
  • Address review comments with additional commits to the same branch
  • The PR updates automatically with each push

5. Merge and Deploy

Once approved and green:


# Merge via CLI or UI
gh pr merge feature/add-user-profile --squash --delete-branch

# The merge triggers deployment
# CI/CD pipeline detects main branch update and deploys

Most teams use squash merges to keep main history clean, but some prefer merge commits for topology preservation.

Production Failure Scenarios + Mitigations

ScenarioWhat HappensMitigation
Bad merge reaches productionA bug slips through review and CIFeature flags allow instant rollback without code changes; revert the merge commit
CI is green but production breaksTests don’t cover the failure modeAdd canary deployments; monitor error rates post-deploy; implement automated rollback
Conflicting PRsTwo PRs modify the same file, only one can merge firstCommunicate in PR comments; rebase the second PR on updated main before merging
Long-running feature branchBranch diverges from main, merge conflicts pile upRebase on main daily; break large features into smaller, mergeable chunks
Deploy pipeline failureMerge succeeds but deployment failsDeployment should be atomic; failed deploys auto-rollback; never leave main in a broken state

Deployment Verification Checklist

After each merge to main, verify the deployment succeeded:

  • CI pipeline completed with all green checks
  • Deployment logs show successful rollout with correct commit SHA
  • Health endpoint responds with 200 OK
  • Error rate in monitoring is within normal baseline (< 1% increase)
  • Key user journeys pass smoke tests (login, core feature, checkout)
  • No new Sentry/alerting errors in the last 5 minutes
  • Database migrations (if any) completed successfully
  • Feature flags for the new feature are in the intended state
  • Rollback procedure is documented and tested if this is a high-risk deploy

Trade-offs

AspectAdvantageDisadvantage
SimplicityOne permanent branch, easy to understandNo structure for complex release management
SpeedMerge and deploy in minutesRequires excellent automated testing
Code reviewEvery change gets reviewed before mergeCan become a bottleneck for large teams
HistoryClean linear history with squash mergesLoses feature branch topology information
RiskSmall, frequent changes are low-riskEvery merge to main is a production change
Learning curveNew developers can start contributing immediatelyRequires discipline around CI and feature flags

Implementation Snippets

Branch Protection Rules

# GitHub repository settings (via API or UI):
# Required pull request reviews: 1
# Dismiss stale reviews: enabled
# Require status checks: build, test, lint
# Require branches to be up to date: enabled
# Include administrators: enabled
# Restrict pushes that create matching files: enabled

GitHub Actions — CI Pipeline

# .github/workflows/ci.yml
name: CI
on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck
      - run: npm test -- --coverage

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: ./scripts/deploy.sh
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

Feature Flag Integration


// src/features/userProfile.ts
import { isFeatureEnabled } from '@/utils/featureFlags';

export function UserProfilePage() {
  if (!isFeatureEnabled('user-profile')) {
    return null; // Or redirect to a fallback
  }

  return <UserProfile />;
}

// Feature flag evaluation
// src/utils/featureFlags.ts
export function isFeatureEnabled(flag: string): boolean {
  const flags = process.env.FEATURE_FLAGS || '{}';
  return JSON.parse(flags)[flag] === true;
}

Quick Revert Script


#!/bin/bash
# scripts/revert-last-merge.sh
# Revert the last merge commit on main

git checkout main
git pull origin main

# Find the last merge commit
LAST_MERGE=$(git log --oneline --merges -1 --format="%H")

if [ -z "$LAST_MERGE" ]; then
  echo "No merge commits found on main"
  exit 1
fi

echo "Reverting merge: $LAST_MERGE"
git revert -m 1 "$LAST_MERGE"
git push origin main

echo "Revert pushed. CI will redeploy the previous version."

Observability Checklist

  • Logs: Log every PR merge event with author, PR number, and commit SHA
  • Metrics: Track PR cycle time (open to merge), deployment frequency, and mean time to recovery
  • Traces: Correlate each deployment with the PR that triggered it and any subsequent incidents
  • Alerts: Alert on deployment failure rate > 5%, PRs open longer than 3 days, or main branch CI failures
  • Dashboards: Display deployment frequency, lead time for changes, change failure rate, and MTTR (DORA metrics)

Security and Compliance Notes

  • Branch protection: Required reviews and status checks prevent unauthorized merges to main
  • Signed commits: Require GPG-signed commits for cryptographic authorship verification
  • CODEOWNERS: Use CODEOWNERS file to require specific team reviews for sensitive directories
  • Secrets scanning: Enable GitHub secret scanning to prevent credential leaks in PRs
  • Audit log: GitHub’s audit log tracks all repository events including branch protection changes
  • Compliance gap: GitHub Flow lacks formal release artifacts — supplement with deployment logs and change tickets if required by your compliance framework

Common Pitfalls and Anti-Patterns

  1. The Staging Branch — Adding a staging branch turns GitHub Flow into a half-baked Git Flow. Either commit to continuous deployment or use a different model.
  2. Skipping Code Review — Merging your own PRs without review defeats the only quality gate. Enforce branch protection rules.
  3. Massive PRs — Pull requests with 50+ files are impossible to review effectively. Break features into smaller, reviewable chunks.
  4. Ignoring CI Failures — Allowing merges with failing checks means main is not always deployable. Make CI mandatory.
  5. No Feature Flags — Without feature flags, every merged feature is immediately visible to users. This couples deployment to release.
  6. Long-Lived Branches — Feature branches that exist for weeks defeat the purpose. Merge small, merge often.
  7. Direct Commits to main — Bypassing PRs for “emergency fixes” creates inconsistency. Use the same process for everything.

Quick Recap Checklist

  • main branch is always deployable and represents production
  • Every change starts as a feature branch from main
  • Pull requests require at least one review before merge
  • CI pipeline runs tests, linting, and type checks on every PR
  • Merged PRs trigger automatic deployment to production
  • Branch protection rules prevent direct pushes to main
  • Feature flags control feature visibility independent of deployment
  • PRs are kept small and focused for effective code review
  • Failed deployments trigger automatic rollback
  • DORA metrics are tracked and reviewed regularly

Interview Q&A

What is the key difference between GitHub Flow and Git Flow?

GitHub Flow has one permanent branch (main) while Git Flow has two (main and develop) plus temporary release and hotfix branches. GitHub Flow assumes every merge to main is deployable, making it ideal for continuous deployment. Git Flow assumes releases are scheduled events requiring a stabilization period on a release branch.

In practice, GitHub Flow is simpler and faster but requires stronger automated testing and feature flag infrastructure to manage risk.

How do you handle a production bug in GitHub Flow?

Create a hotfix branch from main, fix the bug, open a PR, get it reviewed and merged — the same process as any other change. The speed comes from the small scope of the fix, not from bypassing the process.

If the fix needs to go out immediately, use a feature flag to disable the broken feature while the fix goes through the normal pipeline. This is faster than waiting for a merge and deployment cycle.

Why are feature flags important in GitHub Flow?

Feature flags decouple deployment from release. You can merge code to main and deploy it to production without exposing the feature to users. This allows you to deploy frequently while controlling when features become visible.

They also enable progressive rollout — enabling a feature for 10% of users, then 50%, then 100% — and instant rollback by toggling the flag off without deploying new code.

Should you use squash merge or merge commit in GitHub Flow?

Squash merge is the most common choice in GitHub Flow because it keeps main history clean and linear — each PR becomes a single commit. This makes git log easier to read and git bisect more straightforward.

Merge commits preserve the feature branch topology, which is useful for understanding what changes shipped together. Teams that value history preservation over cleanliness may prefer this approach.

The key is consistency — pick one strategy and enforce it via repository settings.

Resources

Category

Related Posts

Choosing a Git Team Workflow: Decision Framework for Branching Strategies

Decision framework for selecting the right Git branching strategy based on team size, release cadence, project type, and organizational maturity. Compare Git Flow, GitHub Flow, and more.

#git #version-control #branching-strategy

Git Flow: The Original Branching Strategy Explained

Master the Git Flow branching model with master, develop, feature, release, and hotfix branches. Learn when to use it, common pitfalls, and production best practices.

#git #version-control #branching-strategy

Git Release Branching and Hotfixes: Managing Versions in Production

Master release branching and hotfix strategies in Git. Learn version branches, emergency fixes, backporting, and how to manage multiple production versions safely.

#git #version-control #release-management