Lesson 28 of 29 intermediate 6 min read

Before this:Branches explainedPull requests & code review

Branching strategies: trunk, GitHub Flow & Git Flow

Key takeaways A branching strategy is a team agreement about how you use branches and pull requests. Trunk-based development keeps everyone on one trunk with tiny, frequent merges and hides unfinished work behind feature flags. GitHub Flow is the lightweight default: branch → PR → review → merge → deploy, with main always deployable. Git Flow adds develop, plus feature/release/hotfix branches — powerful for versioned releases but heavy for continuous deployment. Branch protection and CI are what make small, frequent merges safe. Choose by team size and release cadence, then be consistent.

Git doesn’t impose a workflow — branches are just pointers. A strategy is the convention your team layers on top: which branches are long-lived, how work flows into them, and when you ship. The three below cover most teams. Picking one deliberately matters more than which one you pick.

Trunk-based development

Everyone integrates into a single trunk (main) frequently — at least daily — through very short-lived branches that live hours, not weeks. Work too big to finish in a day is merged incrementally and hidden behind a feature flag until it’s ready to switch on:

$ git switch -c quick-fix
# ... small change, opened as a PR, reviewed, merged the same day ...
$ git switch main
$ git pull

Because branches barely diverge, merges are trivial and merge conflicts are rare. The trade-off is discipline: it demands strong CI, feature flags for incomplete work, and a culture of small changes. It’s the model behind continuous delivery and the choice of many high-velocity teams.

GitHub Flow

The pragmatic default for most web projects, and the one this path has quietly taught throughout. There’s one long-lived branch — main, always deployable — and a single, simple loop:

main ──●──────────────●─────────►  (always deployable)
        \            /
         ●──●──●────●   feature branch → PR → review → merge → deploy
  1. Branch off main for any change.
  2. Push and open a pull request.
  3. Review and let CI run.
  4. Merge into main.
  5. Deploy main.

It’s easy to teach, keeps main releasable, and fits teams that deploy often. Branches are short-lived (though usually longer than trunk-based) and there’s no separate integration branch to manage.

Git Flow

Git Flow is the heavyweight, built for versioned, scheduled releases. It uses two long-lived branches plus three kinds of supporting branch:

Branch Lives Purpose
main forever production; every commit is a tagged release
develop forever integration branch for the next release
feature/* short one feature, branched from and merged to develop
release/* short stabilise a release; branched from develop, merged to main and back
hotfix/* short urgent production fix; branched from main, merged to main and develop
$ git switch develop
$ git switch -c feature/payments     # work happens off develop
# ... later, cut a release ...
$ git switch -c release/1.5 develop  # stabilise, then merge to main and tag

That structure is genuinely useful when several released versions are live at once and need independent hotfixes — desktop apps, mobile apps, libraries, firmware. For a continuously deployed web service, the develop branch and release ceremony usually add overhead with little payoff.

How branch protection and CI support each

None of these strategies is safe on trust alone. Branch protection enforces the rules a strategy assumes — requiring PR review and passing status checks before anything lands on the protected branch, and blocking force-pushes. CI runs the tests and linters that prove a branch is mergeable, which is what makes “main is always deployable” credible rather than aspirational.

The faster the strategy, the more it leans on this safety net: trunk-based development is only sane because CI catches regressions on every tiny merge. Add automated checks via GitHub Actions and require them in branch protection, and small frequent merges stay trustworthy.

Choosing one

There’s no universally best model — fit it to your context:

If your team… Lean toward
Deploys a web app continuously, small/medium team GitHub Flow
Deploys many times a day, mature CI, uses feature flags Trunk-based
Ships versioned releases maintained in parallel Git Flow
Is a solo project or learning GitHub Flow (simplest that scales)

Rules of thumb: shorter release cadence and larger teams favour shorter-lived branches (trunk-based / GitHub Flow); discrete versioned releases justify Git Flow’s structure. Whatever you pick, the real win is consistency — a team that agrees on one model and documents it beats a “perfect” model nobody follows the same way. Define how you merge vs rebase too, and write it down in your contributing guide.

Quick check: which situation most justifies Git Flow's extra complexity?

Recap

  • A branching strategy is a team convention over Git’s branches and pull requests — pick one deliberately.
  • Trunk-based: one trunk, tiny frequent merges, feature flags for unfinished work; needs strong CI.
  • GitHub Flow: branch → PR → review → merge → deploy, main always deployable — the lightweight default.
  • Git Flow: main + develop plus feature/release/hotfix — worth it for versioned, parallel releases.
  • Branch protection + CI enforce and prove the safety each model assumes.
  • Choose by team size and release cadence, then stay consistent.

Next up: the habits that make any strategy work — commit hygiene & best practices.

Frequently asked questions

What is trunk-based development?

Trunk-based development keeps a single long-lived branch (the trunk, usually main) that everyone integrates into frequently — typically at least daily — through very short-lived branches or even direct commits. Unfinished features are hidden behind feature flags rather than kept on long branches, which keeps merges small and avoids painful divergence. It pairs naturally with continuous integration and continuous delivery.

What is the difference between GitHub Flow and Git Flow?

GitHub Flow is lightweight - branch off main, open a pull request, review, merge, and deploy, with main always deployable. Git Flow is heavier, with two long-lived branches (main and develop) plus dedicated feature, release, and hotfix branches and a defined process for moving between them. GitHub Flow suits continuous web deployment; Git Flow suits versioned software with scheduled releases, at the cost of more overhead.

When is Git Flow's complexity worth it?

Git Flow earns its complexity when you ship discrete, versioned releases that must be maintained in parallel — desktop or mobile apps, libraries, firmware, or any product where several versions are live at once and need hotfixes independently. For a continuously deployed web service, Git Flow’s develop branch and release ceremony usually add overhead without benefit; trunk-based development or GitHub Flow fit better.

How do branch protection and CI support a branching strategy?

Branch protection enforces the rules a strategy assumes — requiring pull request reviews and passing status checks before anything lands on the protected branch, and blocking force-pushes. CI runs the tests and linters that prove a branch is safe to merge, which is exactly what makes “main is always deployable” credible. Together they let small, frequent merges stay safe, which is what trunk-based and GitHub Flow depend on.