August 11, 2026
Branching strategy: main, pre, and dev
Why three long-lived branches
Most teams get away with main plus feature branches. Once you're operating services that other systems depend on in real time — payment processing, reconciliation jobs, anything where a bad deploy has a blast radius — you want a rehearsal environment that behaves like production before code actually reaches it. That's what pre is for.
main— production. Every commit here is deployable and, ideally, already running.pre— pre-production / staging. Mirrors production infrastructure and data shape as closely as practical. This is where integration issues, migration edge cases, and config drift show up before customers see them.dev— integration branch for work in progress. Where feature branches land first, before they're stable enough forpre.
Naming branches that come off main
Every short-lived branch should say what it is and what it touches, at a glance:
feature/<ticket-or-name>— new functionality. e.g.feature/ria-remittance-apifix/<ticket-or-name>— bug fixes. e.g.fix/reconciliation-race-conditionhotfix/<ticket-or-name>— urgent fix branched directly frommainto patch production, bypassing the normaldev → pre → mainflow when something is actively broken.chore/<ticket-or-name>— maintenance: dependency bumps, refactors with no behavior change, CI tweaks.docs/<ticket-or-name>— documentation only.
Keep the branch name traceable to a ticket ID when you have an issue tracker — it turns git log into a map back to context.
The two-step PR flow
The core rule: nothing reaches main without having proven itself on pre first, except hotfixes.
- Branch off
dev(ormain, for hotfixes) using the prefixes above. - Open a PR from the
fix//feature/branch intopre. This is where CI runs against a production-like environment, and where a teammate or QA actually exercises the change. - Once
preis green and the change has been verified — manually or via automated smoke tests — open a second PR from that samefix//feature/branch intomain. - Deploy
main. Tag the release if you version deploys.
Note the second PR is from the same feature branch, not from pre itself. pre is a shared integration branch — by the time your change is verified, it may already contain other people's unrelated, still-in-flight work. Merging pre → main would drag all of that along with you. Merging your own branch into main ships exactly what you tested, nothing more.
This means pre is always a superset of what's about to ship, and main never receives untested surface area. If a change fails on pre, it never gets the chance to fail on main.
Handling hotfixes
Production incidents can't wait for the full pipeline. Branch hotfix/<name> directly off main, PR straight into main, deploy, then backport the same commit into pre and dev so the branches don't silently diverge. Skipping this step is how the same bug reappears three weeks later after the next regular release.
Keeping branches from rotting
- Delete feature branches after merge — a stale branch is a stale mental model of the code.
- Rebase or merge
mainback intodevregularly sodevdoesn't drift far enough that merging becomes painful. - Treat
preas disposable: if it gets into a broken state that isn't a real bug, reset it frommainplus whatever's mid-flight, rather than debugging a branch whose only job is to catch bugs.
More posts
What actually happens between tapping a card and the terminal saying "Approved"
The two-to-three second round trip of a card payment, traced hop by hop: terminal, acquirer, card network, issuer, and back — plus why authorization and settlement are two completely different processes.
Migrating a REST service safely: reusing E2E tests to verify external side effects
How to migrate a REST service to a new stack without a regression, by writing the end-to-end test suite once and reusing it both to lock in behavior during the migration and to verify the external services it talks to afterward.
Running old and new in parallel: coexistence during a partial migration
A migration is rarely a single cutover. Here's how to let a partially migrated system and the legacy one it's replacing serve traffic at the same time, safely, until the cutover is actually done.