Skip to main content

Repository and branching

A branching model is a contract about how change reaches production. This one is deliberately simple: short-lived feature branches, three long-lived environment branches, promotion by pull request, and no direct pushes.

Long-lived branches​

BranchEnvironmentPurposeProtection
mainProductionStable, released codeTwo reviews, all checks, no direct push, no force push
stageStagingIntegration and user acceptance testingOne review, all checks
devDevelopmentOngoing integration of completed workOne review, build and unit tests

A team that deploys continuously may collapse stage into an ephemeral environment. The rule that does not bend: production is reached only through a reviewed pull request from a branch that has passed its gates.

Short-lived branches​

Created from dev, merged back within days rather than weeks.

feature/<short-description>
bugfix/<short-description>
hotfix/<short-description>
chore/<short-description>
TICKET-123-feature-name

Long-lived feature branches recreate the merge conflicts that trunk-based development avoids. If a branch lives longer than a sprint, split it.

Commit messages​

TICKET-123 Add retry with backoff to payment capture

The gateway returns 503 under load without retry, causing
avoidable failures on checkout. Adds three attempts with
exponential backoff and a circuit breaker after five
consecutive failures.

Rules:

  • Start with the ticket identifier.
  • Subject in imperative mood, under 72 characters.
  • Body explains why, not what — the diff shows what.
  • Reference breaking changes explicitly.

Pull request workflow​

  1. Create the branch From dev, with a name that states the change.

  2. Open a draft early A draft PR makes the change visible while it is still cheap to redirect.

  3. Pass the gates Build, unit tests, static analysis, secret scan, and infrastructure plan where applicable.

  4. Review At least one reviewer; two for infrastructure, security-sensitive paths, or anything that changes a data store.

  5. Merge to dev Squash merge for a single coherent commit. Linear history.

  6. Promote PR from dev to stage after development validation; PR from stage to main after UAT.

  7. Deploy The pipeline deploys the merged branch. No manual deployment step.

  8. Delete the branch The branch has served its purpose; keeping it invites divergence.

What reviewers check​

Code review is not a style exercise — linters handle style. Reviewers look for:

  1. Correctness under failure. What happens when the dependency times out, the queue backs up, or the request is retried?
  2. Blast radius. What breaks if this is wrong, and how quickly would we know?
  3. Test quality. Do the tests exercise behaviour or implementation details?
  4. Security. Does this widen a permission, log a secret, or trust input?
  5. Operability. Can this be diagnosed in production from logs and metrics?
  6. Reversibility. Can this change be rolled back without data loss?

Branch protection​

Rulemainstagedev
Require pull requestYesYesYes
Required approvals211
Dismiss stale approvals on new commitsYesYesYes
Require status checksYesYesYes
Require branch up to dateYesYesNo
Require conversation resolutionYesYesNo
Restrict who can pushYesYes—
Allow force pushNoNoNo
Allow deletionNoNoNo
Require signed commitsPer customerPer customerPer customer

Hotfixes​

A production defect that cannot wait for the normal promotion path:

  1. Branch hotfix/<description> from main.
  2. Fix, test, and open a PR to main with an incident reference.
  3. Review and deploy through the same pipeline — faster, not bypassed.
  4. Merge main back into stage and dev so the fix is not lost on the next release.

The hotfix does not skip the pipeline. It skips the queue.

Anti-patterns​

  • Direct commits to main "only this once."
  • Long-lived release branches that diverge from main.
  • Force-pushing a shared branch and rewriting others' history.
  • Merging without the required checks because they were slow.
  • Feature flags used to hide a half-finished merge on main indefinitely.