Workflows#
How a team uses Git matters more than which tools they use. The major workflow patterns trade off between change isolation, integration frequency, and release cadence.
Trunk-Based Development#
Everyone commits to a single long-lived branch (main);
short-lived branches if any. The 2026 default for most product
teams; the merge pain is minimum, feedback is fast, and the
branch is always ready to ship. Requires strong tests, feature
flag discipline, and a small-change culture.
Small, frequent merges to
main.Feature flags for incomplete work that is on
mainbut off in production.Releases are tags or branches cut from
main.CI gates merges; the branch is always green.
gitGraph
commit id: "init"
commit id: "feat-A"
branch tiny-fix
commit id: "fix"
checkout main
merge tiny-fix
commit id: "feat-B"
commit id: "feat-C"
commit id: "feat-D"
commit id: "v1.0" tag: "v1.0"
commit id: "feat-E"
Strengths: minimum merge pain, fast feedback, the branch is always ready to ship. Weaknesses: requires strong tests, feature flag discipline, and small change culture. Works at scale (Google, Meta, Netflix).
The 2026 default for most product teams.
GitHub Flow#
A simple branch-and-merge model, probably the most common
workflow on GitHub-hosted projects. Every change goes through
a topic branch and a PR; CI gates the merge; main is
always deployable. No explicit support for parallel release
lines.
mainis always deployable.Create a topic branch for any change.
Open a PR; CI runs; review happens; merge to
main.Deploy
maincontinuously or on cadence.
gitGraph
commit
branch feature/login
commit id: "scaffold"
commit id: "happy path"
commit id: "tests"
checkout main
merge feature/login
commit id: "deploy"
branch feature/profile
commit id: "page"
commit id: "validation"
checkout main
merge feature/profile
commit id: "deploy"
Strengths: simple, well-supported by every platform. Weaknesses: no built-in story for parallel release lines.
Probably the most common workflow on GitHub-hosted projects.
GitLab Flow#
GitHub Flow plus environment branches. main is the
integration branch; staging and production (or per-
environment branches) receive promotions via merges from one
to the next. Useful when deploys aren’t continuous and you
want explicit promotion gates.
mainis the integration branch.stagingandproduction(or per-environment) branches receive promotions.Promote with merges from one to the next.
gitGraph
commit id: "init"
branch staging
commit id: "stage-base"
branch production
commit id: "prod-base"
checkout main
branch feature/x
commit id: "feat"
checkout main
merge feature/x id: "merge"
commit id: "more"
checkout staging
merge main id: "promote"
checkout production
merge staging id: "release" tag: "v1.0"
Useful when deploys aren’t continuous; replaces ad-hoc tagging with explicit branches.
GitFlow#
The 2010-era heavyweight. Two long-lived branches (main + develop) and three families of short-lived ones; explicit phases for versioned software releases. Outside of versioned products or libraries, most modern teams have moved away from GitFlow.
main, production releases.develop, integration branch.feature/*,release/*,hotfix/*, supporting branches.Releases promoted via release branches; hotfixes branched from main.
gitGraph
commit id: "init"
branch develop
commit id: "dev start"
branch feature/A
commit id: "feat A"
checkout develop
merge feature/A
branch feature/B
commit id: "feat B"
checkout develop
merge feature/B
branch release/1.0
commit id: "release prep"
checkout main
merge release/1.0 id: "v1.0" tag: "v1.0"
checkout develop
merge release/1.0
checkout main
branch hotfix/1.0.1
commit id: "hotfix"
checkout main
merge hotfix/1.0.1 id: "v1.0.1" tag: "v1.0.1"
checkout develop
merge hotfix/1.0.1
Strengths: explicit phases for software with versioned releases. Weaknesses: heavy ceremony, slow integration, prone to long-lived branches and painful merges.
Outside of versioned product or library releases, modern teams have mostly moved away from GitFlow.
Forking Workflow#
Each contributor has a personal fork; PRs come from forks rather than branches in the main repo. The default for open-source contributions because most contributors don’t have write access; required if maintainers want to keep the upstream branch list clean. For internal teams, branching in the same repo is simpler.
sequenceDiagram
participant U as Upstream Repo
participant F as Your Fork
participant L as Local Clone
U ->> F: fork
F ->> L: clone
L ->> F: commit + push
F ->> U: pull request
Note over U: maintainer merges
U ->> L: fetch upstream (sync)
The default for open-source contributions.
Required when contributors don’t have write access.
Adds a step (sync your fork) that some contributors miss.
For internal teams, branching in the same repo is usually simpler.
Pull / Merge Requests#
sequenceDiagram
actor Author
participant Branch as Topic Branch
participant CI as CI
actor Reviewer
participant Main as main
Author ->> Branch: push commits
Branch ->> CI: trigger pipeline
CI -->> Author: green / red
Author ->> Reviewer: open PR
Reviewer ->> Branch: review
Reviewer -->> Author: request changes / approve
Author ->> Branch: address feedback
Branch ->> CI: re-run
CI -->> Reviewer: green
Reviewer ->> Main: merge
Whatever the branch model, the PR is the unit of review and the place where most engineering judgment gets exercised. The discipline below is what separates a productive review culture from a slow one. Whatever the branch model, the PR is the unit of review.
Small, single concern, ~hundreds of lines max.
Self-explanatory, title and description tell the reviewer the why.
Tested, CI green; tests for the change exist.
Atomic commits, not always, but worth aiming for so each commit could ship independently.
Reviewable, prefer narrow diffs; refactors split from behavior changes.
Common conventions.
Conventional Commits (
feat:,fix:,chore:) for changelog generation.Required reviewers, one or two for normal changes; more for sensitive paths.
CODEOWNERS files to route review by area.
Auto-merge once green and approved.
Commit Hygiene#
The conventions that make commit history a readable artifact years later. Each rule below traces back to a specific failure mode; “what changed” without “why” is useless to your future self; tangled commits can’t be cherry-picked or reverted cleanly.
Imperative mood, “fix bug” not “fixed bug” or “fixes bug”.
Subject < 72 chars; body wraps at 72.
Why > what in the body; the diff already shows the what.
Reference issues in the body, not the subject.
One logical change per commit, when feasible.
Squash-merge or interactive-rebase before merging is fine; quality of
main’s log matters more than perfect feature-branch hygiene.
Release Strategies#
How merges to main turn into actual releases. The four patterns below cover most teams; the right pick depends on how production tolerates change; internal tools can run continuous; library releases need versioning; mobile apps need cadence to match their submission process.
Continuous, every merge to main is a release. Requires strong tests and feature flags.
Cadence, release at a fixed cadence (weekly, biweekly).
Versioned, semantic versioning; each release is a tag plus release notes.
Release branches, cut from main, only critical fixes back-ported.
Pair with one of.
Conventional Commits + automated changelog.
Changesets for monorepos.
Monorepo vs. Polyrepo#
The two repository-structure philosophies. Both are professional choices. The choice often follows team structure (Conway’s Law again) more than any technical argument; what matters is whether the build tooling investment matches the choice.
Monorepo, one repo for many projects. Atomic cross-project changes, unified tooling, single CI. Heavy build tooling investment.
Polyrepo, one repo per project. Independent release cycles, smaller blast radius, simple CI.
Both are professional choices. The choice often follows the team structure (Conway’s law) more than a technical argument.
Common Pitfalls#
The five workflow mistakes that show up regardless of the branch model. Each one trades a small short-term convenience for a larger long-term cost, merge debt, broken collaborator work, lost bisect history, missed regressions, and the “urgent” changes that turn out to be exactly the riskiest.
Long-lived branches, merge debt grows; integrate often.
Force-pushing shared branches, breaks others’ work; use
--force-with-leaseand only on private branches.Squash everything blindly, you lose the ability to bisect within a feature. Squash thoughtfully.
Living without CI on PRs, the workflow is broken without it.
Skipping reviews “just this once”, the riskiest changes most often have urgency attached.