Branching & PRs
We work on main, in short bursts. Branch off it, do one small thing, open a PR, merge back the same day or two. Long-lived branches drift and turn every merge into a negotiation. Never commit straight to main.
Each branch is one unit of work that starts from main and returns to it as a single squashed commit. Two branches in flight at once is normal; a branch open for a week is a smell.
Naming a branch
type/short-description, kebab-case, so the branch says what it is at a glance.
| Type | For | Example |
|---|---|---|
feat | A new capability | feat/roadmap-releases |
fix | A defect in shipped behavior | fix/request-back-button |
docs | Docs only | docs/pd-onboarding |
design | Design or visual work | design/glide-request-keyboard |
chore | Tooling, deps, config | chore/bump-drizzle |
Keep the description a few words. The issue or context lives in the PR, not the branch name.
Commits
We write Conventional Commits: type(scope): subject. The scope is the area touched, the subject is the change in the imperative.
feat(roadmap): add release notes field to initiatives
fix(web): keep the back button on the request detail page
docs(glide): make Above-the-fork per-attribute
Types in use: feat, fix, docs, test, chore, content. Two rules that matter more than the format:
- Small and atomic. One commit is one self-contained change that builds and passes on its own. If you cannot describe it in one line without “and”, it is two commits.
- Green at every commit. You should be able to check out any commit on the branch and have it work. This is what makes a revert clean.
When AI wrote a meaningful part of the change, add the trailer:
Co-Authored-By: Claude <noreply@anthropic.com>
Opening a PR
Base is main. Title is a one-liner in the same type: description shape as a commit. The description follows one format so a reviewer can read any PR the same way:
- What changed · one line.
- Why · one line, the problem it solves.
- Before / After · the observable difference, with a number when you have one.
- Risks & Mitigation · even low risk. What could break, and the lever that catches it (a flag, a test, a revert).
- Testing · what you ran and what you checked by hand.
- Rollback · for anything non-trivial, the exact way back (flip the flag, revert the commit).
Here is that format filled in for a small, flag-guarded feature:
Notice what makes it good: it is short, the risk is named even though it is low, and the way back is one line a stressed on-call can follow. The same template lives in the repo’s CLAUDE.md. It exists so risk is stated out loud, not so the PR is long.
What a good PR looks like
Small is the whole game. A PR a reviewer can hold in their head gets read carefully and merged fast. A large one gets skimmed and rubber-stamped, which is where bugs walk in. If a PR touches many files for many reasons, split it. Ship the refactor, then the feature, in that order, as separate PRs.
- One reason to exist. A PR does one thing. “Rename this and also add that” is two PRs.
- Reviewable in one sitting. If you cannot review it in ten minutes, neither can anyone else.
- Self-reviewed first. Read your own diff before you request a review. You will catch the debug log, the stray file, the half-named variable.
- CI green before review. The PR checks run lint, typecheck, build, and tests on the affected packages. Do not hand a red PR to a person.
- AI review addressed. When an AI reviewer comments, resolve the real issues and say why you skipped the rest.
Merge with squash, so the branch collapses to one clean commit on main, and delete the branch. Whether a change needs another engineer’s eyes before merge is a separate question, answered in Code Review: most changes are reversible and do not.
Related: Code Review, Feature Flags, Testing & TDD, Releasing & Rollback