Code review
Two things about review here are not the same as on other forges: pull requests stack, and review threads survive a force-push. Both fall out of the engine underneath rather than being features bolted onto it — see The storage engine.
Stacked pull requests
Section titled “Stacked pull requests”A pull request can name another pull request as its parent. That makes a stack: each PR targets the branch of the one below it, and the bottom of the stack targets the default branch.
main ← A ← B ← C ↑ ↑ bottom topThe point is that each PR in the stack is reviewed and approved on its own, against only its own diff. You do not have to hold “the parts of this 900-line diff that belong to the refactor” in your head while reviewing the feature that sits on top of it.
Stacks are linear — one child per parent — and bounded at 32 deep.
Merging the bottom
Section titled “Merging the bottom”This is the part that is usually painful elsewhere. When a PR in a stack merges, its children are re-parented onto its parent, and each child’s base branch is retargeted onto the branch the merged PR was targeting.
Both halves move together, which is what makes the stack stay correct:
- The pointer moves — a 3-PR stack
A → B → Ccollapses toA → CwhenBmerges. - The base ref moves —
Cis retargeted onto whateverBwas targeting.
Without the second half a child would keep targeting a source branch that never advances again, and its mergeability would answer the wrong question forever. Because the bottom PR targets the default branch, merging the bottom hands the default branch straight to its child, and the stack simply shortens.
Review threads that survive a rebase
Section titled “Review threads that survive a rebase”A review thread is anchored to a file, a line, and a commit. When the PR’s source branch advances — new commits, an amend, a force-push — every open thread is re-aligned against the new head rather than being orphaned.
The alignment is per-thread, and it is decided by reading the file rather than by trusting line numbers:
| At the new head | Outcome |
|---|---|
| File is gone | thread marked outdated |
| File is byte-identical | anchor advances, line unchanged |
| File changed, the line’s text survives | anchor and line number advance |
| File changed, the line’s text is gone | thread marked outdated |
The third row is the one that matters day to day: insert twenty lines above a comment and the thread follows its line down the file instead of pointing at whatever now occupies the old line number. Threads are matched on the text of the line, using a diff alignment, not on position.
Changes keep a stable identity across a force-push because the engine tracks a change’s identity separately from the commit that currently expresses it, so a PR whose branch was rewritten is still recognisably the same change.
Merge gating
Section titled “Merge gating”Branch protection rules are keyed on a branch pattern, using the same glob
dialect as workflow triggers (* stays within one / segment, ** crosses
them). Exactly one rule applies to a branch — an exact-name rule wins,
otherwise the longest matching pattern does. Rules do not merge, and a
branch with no matching rule has no gate.
A rule can require:
- status checks — named contexts, or CI-derived
"<workflow> / <job_key>"names, all of which must be green - approving reviews — a count
- up-to-date with the target branch
- conversation resolution
- enforcement on admins
Merging
Section titled “Merging”The merge is a real git operation, not a pointer swap:
- fast-forward when the target branch has not diverged;
- a two-parent merge commit, produced by a three-way tree merge, when it has;
- blocked as a conflict when both sides changed the same path.
Auto-merge
Section titled “Auto-merge”Someone with write access can arm an open PR to merge when it goes green. The merge is attributed to whoever armed it, not to whoever pushed the commit that turned the checks green.
Behaviour worth knowing:
- Arming a PR that is already mergeable merges it immediately rather than leaving it armed.
- A failing check leaves the PR open and still armed.
- A new head disarms it. Pushing new commits requires fresh merge intent — nobody’s earlier “merge this when green” was cast over code they had not seen.
Where this stops
Section titled “Where this stops”- Stacks are linear and capped at 32; there is no branching stack.
- Merging re-parents and retargets children but does not rebase them.
- Cross-repository stacks do not exist — a stack lives inside one repository.
See also
Section titled “See also”- Planning — linking a PR to the work it closes.
- The storage engine — where change identity comes from.
- Project status — what is ready today.