A branching strategy is a team agreement about how code moves from a laptop to production. The right one reduces merge conflicts, keeps main deployable and makes it obvious what is released. For small teams, simpler is almost always better.
The three strategies you will hear about
Trunk-based development
Everyone integrates into main (the trunk) at least daily, using very short-lived branches or direct commits behind feature flags. It needs good automated tests and a fast CI pipeline, and it rewards teams that deploy often.
GitHub Flow
A lightweight variant that most small teams adopt naturally:
- Branch from
mainfor each change. - Open a pull request early.
- Get a review and green CI.
- Merge to
mainand deploy.
main is always deployable. There are no long-lived develop or release branches.
Git Flow
Uses main, develop, feature, release and hotfix branches. It was designed for software with scheduled, versioned releases — such as installable apps or libraries supporting several versions. For continuously deployed web applications it usually adds ceremony without much benefit.
| Strategy | Best for | Main cost |
|---|---|---|
| Trunk-based | Frequent deploys, strong CI | Needs feature flags and discipline |
| GitHub Flow | Most small web teams | PRs can linger if reviews are slow |
| Git Flow | Versioned, scheduled releases | Many long-lived branches, more merges |
Recommendation for most small teams: start with GitHub Flow and keep branches short-lived.
Conventions that make any strategy work
Name branches predictably
feature/search-autocomplete
fix/login-redirect-loop
chore/upgrade-node-20
docs/api-pagination
Keep branches short-lived
A branch open for two weeks accumulates conflicts and becomes risky to merge. Aim for pull requests that can be reviewed in under 30 minutes. Split large features behind a feature flag if necessary.
Write useful commit messages
feat(search): add debounced autocomplete to header search
Queries fire 250ms after the last keystroke and cancel the
previous request, reducing API calls while typing.
A short imperative summary plus a body explaining why helps whoever reads the history later — often you.
Update your branch safely
git fetch origin
git switch feature/search-autocomplete
git rebase origin/main # replay your commits on the latest main
# resolve conflicts, then:
git push --force-with-lease
Use --force-with-lease, not --force, so you never overwrite a teammate’s pushed work by accident. Never rebase a shared branch that others are committing to.
Automate the boring checks
Branching rules work best when CI enforces them. A minimal GitHub Actions workflow that runs on every pull request:
name: ci
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test
Combine this with branch protection so a pull request cannot be merged until the checks pass. Reviewers can then focus on design and readability instead of spotting failing tests.
Protect main
On GitHub, enable branch protection (or rulesets) for main:
- Require a pull request before merging.
- Require status checks (tests, lint) to pass.
- Require at least one approval.
- Block force pushes and deletions.
Squash, merge or rebase?
- Squash merge turns each PR into one commit on
main. Clean history, one commit per change — a good default for small teams. - Merge commits preserve every commit and show where branches joined. Useful when individual commits are carefully curated.
- Rebase merge keeps individual commits but no merge commit.
Pick one and configure the repository to allow only that option, so history stays consistent.
Releases and hotfixes
Tag releases on main (v1.4.0) so you can always see exactly what was deployed. For an urgent fix, branch from main, fix, review and merge like any other change — with GitHub Flow there is no separate hotfix process to remember.
The best strategy is the one your whole team follows consistently. Write it down in your CONTRIBUTING.md, keep it short, and revisit it when the team or release process changes.
Comments