develop on
git-flow repos, main on trunk-flow repos. See Branch conventions → Which model
applies to check which one a given repo
uses. The title, the description, and the merge strategy together decide what the changelog says.
They also decide how easily someone six months from now can answer “why did this happen?”
Title
- Use the same conventional-commit prefix the squash commit
uses.
feat: …,fix: …,chore(scope): …. The squash-merge takes the PR title as the commit subject verbatim; if the prefix is wrong,release-pleasecomputes the wrong version bump. - No emoji. Same rule as commit subjects: machine-parsed surface, no decoration.
- Under 70 characters. Lengthy context belongs in the body, not the subject line that GitHub truncates in the merged-PR list.
- Imperative mood, present tense: “add netflow firewall rule,” not “added” or “adding.”
- Scope is optional, lowercase, in parens when used:
feat(api): rate-limit token refresh.
Body
Three sections, in this order:## Summary: 1–3 bullets covering why this change exists. Not the diff (the reader sees that); the motivation. If the PR closes a Linear issue or GitHub issue, say so here (Closes JAC-50,Fixes #127).## Test plan: bulleted markdown checklist. What CI runs automatically (bun run build,pnpm test,tofu fmt -check), and what a reviewer still has to verify by hand (browser smoke test, reviewed Terrakube plan, anything CI cannot see). Tick the boxes as work completes.- Optional:
## Security notes: when the change touches credentials, IAM scopes, network exposure, or anything else where the security review is non-obvious from the diff. Empty section = “I considered it and there is nothing to flag” (different from “I did not think about security”).
Merge strategy
Trunk-flow repos (no develop)
- Squash-merge is the default. One PR = one commit on
main. The PR title becomes the commit subject; the PR description becomes the commit body.release-pleasewalks this linear history to compute version bumps. - Any merge method is allowed. Squash is the default; merge and rebase are fine when the history is worth keeping. The merge button pre-fills the PR title as the subject, so it already passes the commit-message rule.
- No force-push to
main. Force-push to your own feature branch is fine while the PR is open.
git-flow repos (has develop)
- PRs target
developby default. Squash is the only method ondevelop, enforced by a ruleset: one PR, one commit ondevelop. develop→mainpromotion is merge-commit only, enforced by a ruleset. Squash and rebase intomainare banned, no exceptions. Therelease-pleaserelease PR is not amainPR: it targetsdevelop, squash-merges there, and the promotion carries it tomain.hotfix/*is the one exception to PR targeting. It branches frommain, its PR targetsmaindirectly with a merge commit (never squash), and a second PR from the hotfix branch (not frommain) carries the fix intodevelop.- No force-push to
mainordevelop. Force-push to your own feature branch is fine while the PR is open.
Review
- CI must be green before merge. CodeQL alerts must be resolved, not dismissed.
- A reviewer’s
request changesblocks merge until the author addresses every comment, either with a fix or with a written reply explaining why no fix is needed. Silent dismissal is not acceptable. - The author drives the conversation. If a reviewer goes quiet for more than 24 h on an open PR, the author pings them in the PR thread or on Slack. The PR stops waiting silently.
Tone in the description and review thread
- Tell hard truths directly. Don’t soften with “perhaps” or “maybe consider.” Disagree explicitly when you disagree.
- ALL CAPS from the requester means refocus immediately. A capitalized correction is the highest-priority signal in the conversation; everything else pauses until that direction is followed.
- Explain complex reasoning. A two-line diff with five lines of justification is fine; an ambiguous diff with no rationale is not.
What this connects to
Commit conventions
The vocabulary the PR title uses. Subject rules, tone, autonomy: all the same.
Branch conventions
Branch type predicts the PR title prefix. One decision, made once.
Git transport
Why private-repo PR pushes go over HTTPS even when public repos use SSH.
CI/CD policy
The release-please flow that consumes the squash-commit subject.