Guide

Git gives a team the same tools however it is organized. How the team uses those tools decides how often they merge, how big each review is, and how many repositories they have to coordinate. This page covers the workflow choices you will meet at work.

Concept

Before you start: a trunk is the main branch, main, that everyone integrates into. A feature flag is a switch in code that turns an unfinished feature on or off without a separate branch.

Trunk-based development vs GitFlow

GitFlow (Vincent Driessen, 2010) uses long-lived develop and main branches, plus feature, release and hotfix branches. It fits software shipped as versioned releases, such as desktop apps, on-premise products and libraries with several supported versions. Its author added a note in 2020 that it is not the right default for continuously delivered web software.

Trunk-based development has everyone integrate into main at least daily, through short-lived branches that live for hours to a couple of days. Unfinished features hide behind feature flags rather than living on branches, so main is always releasable. The DORA research behind Accelerate found trunk-based development among the practices linked with high delivery performance. Most product companies work this way, with CI running on every pull request and every merge.

Small PRs and stacked diffs

PR size is one of the strongest levers on review quality and speed. A 50-line change gets a careful review in minutes. A 2,000-line change gets "LGTM", and bugs hide in it (see code review). Aim for PRs that do one thing and can be reviewed in under 15 minutes. In practice that means under about 200 to 400 changed lines.

When a feature really needs 1,500 lines, split it into a stack. PR 1 adds the schema migration. PR 2, based on PR 1's branch, adds the data access layer. PR 3 adds the API endpoint, and PR 4 adds the UI. Each one is reviewed on its own, and you keep building on top while earlier PRs are still in review.

Stacked diffs came from Phabricator at Facebook, and tools such as Graphite, ghstack and Sapling support them. Plain Git has helped since version 2.38: git rebase --update-refs moves every branch in the stack when you rebase the bottom one.

Monorepo vs polyrepo

A monorepo keeps many projects in one repository. A polyrepo gives each service or library its own.

MonorepoPolyrepo
Cross-project changeOne atomic commit and PRCoordinated PRs and version bumps across repos
Dependency versionsOne version of everything, enforcedEach repo drifts on its own schedule
Code discovery and refactoringGrep everything; large refactors are feasibleHarder to find usages
Tooling costNeeds build tools that only build and test what changed (Bazel, Nx, Turborepo, Pants)Standard tooling works out of the box
Scale limitsGit slows down at very large sizes without helpEach repo stays small
Access controlCoarse; per-directory ownership via CODEOWNERSNatural per-repo permissions

Google keeps most of its code, billions of lines, in one repository on a custom system called Piper. Microsoft moved Windows, around 300 GB, to Git, and built VFS for Git and later Scalar to make it workable. Much of that work, such as partial clone (git clone --filter=blob:none), sparse checkout and the commit-graph file, is now part of mainstream Git.

For a company with tens to hundreds of engineers, a monorepo with good CI caching is usually a productivity win. The deciding question is whether you will invest in build tooling that builds only what changed.

Common mistakes

  • Letting branches live for weeks. Merge conflicts grow with the age of the branch. Integrate at least daily.
  • Shipping an unfinished feature to main without a flag. Use a flag, so the code can merge without being on.
  • Stacking PRs without rebasing the stack. The top branches go stale. Use --update-refs to move the whole stack together.

Check yourself

  • Why does a 50-line PR usually get a better review than a 2,000-line PR? Reviewers can read and test a small change carefully. A large one tends to get a quick approval.
  • What does a feature flag let a trunk-based team do? Merge unfinished code to main safely, and turn it on when it is ready.

Key takeaways

  • Trunk-based development, with short-lived branches and feature flags, suits continuously delivered web products. GitFlow suits versioned releases.
  • Small PRs, or stacks of small PRs, are reviewed faster and more carefully.
  • A monorepo makes cross-project changes atomic, but it needs build tooling to stay fast.
  • Choose the workflow and repository layout by how your team ships, not by habit.

Further learning

Trunk Based Development describes the practice in detail, including feature flags and release branches.

Revisit merge, rebase and squash for the commands behind stacks and squash merges.