Skip to content

Git Branching Workflows

5 min readModern Git Workflows · Branching

A Git branch is a file containing one commit ID. A branching strategy is a set of agreements a team makes about when those files get created, how long they live, and how the work on them reaches production.

The first is a data structure. The second is an engineering and organisational decision. Conflating them is why so much branching advice reads as though Git mandates a particular model. It does not.

Start with Lesson 1

Five things that get called “branching”

Section titled “Five things that get called “branching””

Most arguments about branching are really arguments about different layers. Separating them makes the discussion tractable:

LayerWhat it isWho decides
Git branchesA ref: a file under .git/refs/heads/ holding a commit IDGit
Branch workflowsHow and when branches are created, integrated and deletedYour team
Hosting conventionsPull requests, protected branches, merge queues, required reviewsYour platform
Team policyNaming, review requirements, who may merge, what CI must passYour organisation
Deployment strategyWhich ref triggers which environmentYour delivery pipeline

Git supplies only the first row. Everything below it is convention — which is why two teams can use identical Git commands and run completely different processes, and why “which branching model is correct?” has no answer independent of context.

The technical cost of a branch is negligible — 41 bytes and no copying. The cost that matters is divergence.

Divergence grows with branch lifetime

A trunk lane labelled main with six commits. A branch lane leaves main after the first commit and runs alongside it with three commits, never merging. The gap between the branch tip and the main tip illustrates accumulated divergence.

ABCDEFXYZmainlong-branchEvery commit on main that the branch has not seen is integration work deferred to later.

From the moment a branch is created, two histories evolve independently. Every commit that lands on main and is not on the branch is a difference somebody eventually has to reconcile. That reconciling work does not grow linearly with time — it grows with the interaction between the two sets of changes, which is why a branch that is three times older often takes far more than three times as long to integrate.

This is the single idea the cluster keeps returning to. Almost every branching practice that teams converge on — small pull requests, frequent integration, short-lived branches, feature flags — is a way of keeping divergence small.

  1. Lesson 1: 01. Git Branches ExplainedA Git branch is a movable reference to a commit, not a copy of your project. Learn how branches, HEAD and remote-tracking refs actually work.Beginner → Intermediate11 min read
  2. Lesson 2: 02. Feature Branch WorkflowDevelop each change on its own branch, review it, then integrate. A complete walkthrough of the feature branch workflow and its failure modes.Beginner → Intermediate10 min read
  3. Lesson 3: 03. GitHub FlowGitHub Flow is a lightweight branch-and-pull-request workflow built for continuous delivery. Here is how it works and where its limits are.Beginner → Intermediate11 min read
  4. Lesson 4: 04. Git FlowGit Flow uses develop, release and hotfix branches around main. Learn the model, why it was designed, and why many teams no longer use it.Intermediate10 min read
  5. Lesson 5: 05. Trunk-Based DevelopmentTrunk-based development keeps everyone integrating into one branch continuously. Learn the practices and the engineering maturity it requires.Intermediate12 min read
  6. Lesson 6: 06. Short-Lived BranchesThe longer a branch lives, the more it diverges from what it must integrate with. Learn why branch lifetime drives merge pain.Beginner → Intermediate8 min read
  7. Lesson 7: 07. Release BranchesRelease branches freeze a version for stabilisation while development continues. Learn when they earn their complexity and when they do not.Intermediate9 min read
  8. Lesson 8: 08. Choosing a Branching StrategyCompare feature branches, GitHub Flow, Git Flow and trunk-based development against your team size, release model and CI maturity.Intermediate14 min read

The sequence is deliberate.

Lesson 1 establishes what a branch actually is, because several popular misconceptions — that a branch copies your files, that it is a directory, that deleting it deletes work — make strategy impossible to reason about.

Lesson 2 covers the feature branch workflow, the base pattern nearly every other model is a variation on.

Lessons 3–5 cover the three named models teams actually argue about: GitHub Flow, Git Flow and trunk-based development. Each gets a fair treatment, including where it fits badly.

Lessons 6–7 cover two practices that cut across models: keeping branches short-lived, and using release branches when you genuinely need to stabilise a version.

Lesson 8 is the decision guide that ties the cluster together — a structured comparison rather than a recommendation.

Branching models were mostly designed before continuous delivery was normal, and automation changes what a branch means.

When every push runs a test suite, a branch stops being purely a place to keep work and becomes a unit of validation. When merging to main triggers a deployment, main stops being a place to integrate and becomes a declaration that this is what production should run. Models that assume a human decides when to cut a release fit badly against a pipeline that deploys on merge.

Three questions usually settle more of the debate than the model names do:

  1. What must pass before a change reaches main? If the answer is “a full test suite that catches most regressions”, short-lived branches straight to main are viable. If it is “a manual QA cycle that takes two days”, you need somewhere for changes to accumulate while that happens.
  2. What happens automatically when main changes? Deploy to production, deploy to staging, or nothing at all. Each implies a different tolerance for a broken main.
  3. How quickly can you undo a bad change? A team that can revert and redeploy in minutes can afford to integrate aggressively. A team shipping firmware cannot.

A model that suits the answers to those three questions will work. One that does not will be quietly worked around, which is how teams end up with a documented process nobody follows.

These recur regardless of which strategy a team picks:

  • Treating branches as long-term storage. A branch nobody has integrated for a month is not work in progress; it is a merge problem accruing interest.
  • Merging main into a feature branch repeatedly without understanding why. Syncing is reasonable; doing it reflexively to “fix” conflicts often just spreads the same conflict across several commits.
  • Adopting a model’s vocabulary without its practices. Git Flow without releases, or trunk-based development without adequate test coverage, produces the costs of the model and none of the benefits.
  • Assuming branch protection is a workflow. Rules stop bad merges; they do not decide when a branch should exist.
  • Copying a model from a very different context. The right strategy for a hundred-engineer SaaS product is rarely right for a three-person library.

You need the Git model from Pillar 1, specifically:

  • Understanding HEAD — what a ref is, and how HEAD points at a branch which points at a commit. Lesson 1 builds directly on this.
  • Git Objects Explained — commits as immutable objects with parent links. Divergence is easiest to understand as a shape in the commit graph.
  • Git Repository Structure — where branch refs actually live on disk.

If those are familiar, you have everything you need. If not, Lesson 1 recaps the essentials and links back rather than repeating them.

Branch names are conventions, not Git features. main, master, develop, trunk and release/1.2 are all ordinary refs; Git treats them identically. The only special case is that a repository’s default branch is recorded in configuration so that git init and clones know where to start.

This cluster uses main throughout, which matches current defaults on the major hosting platforms. If your repository uses a different name, substitute it — nothing in the mechanics changes.

By the end of this cluster you should be able to answer, for a specific team and product:

  • Whether a change needs its own branch at all
  • How long a branch should live before integration becomes expensive
  • Whether your release model needs a release branch or is better served by tagging main
  • Whether your CI and test coverage can actually support trunk-based development
  • What branch protection should require before a merge is allowed
  • Which named model to start from, and which parts of it to discard

Start with what a branch actually is. Almost every strategy question becomes easier once the data structure is clear.