Skip to content

Epic (feature) branches

Trial — agreed 12 Jun 2026

This workflow was proposed and agreed as an experiment in the weekly engineering check-in (12 Jun 2026). We're trying it for distinct, multi-ticket features; expect it to be refined. Feedback welcome — raise it in the retro.

Why

Our default is one branch per ticket merged straight to develop (see Branching & releases). That breaks down for a feature/epic made of several tickets:

  • The backend ticket merges and ships while the frontend is still in progress, so the epic looks partly "done" but the feature isn't usable.
  • If the epic contains a breaking change to existing behaviour, you can't safely ship half of it — you need every ticket before it goes out.
  • Big single PRs (one grew to ~6,000 lines) are painful to review and drown in Copilot comments.

The goal: a feature ships as one atomic unit when the whole epic is done, while the work still lands in small, independently reviewable pieces.

The model

Create a long-lived epic branch named after the epic. Each ticket branches off the epic branch and is PR'd back into the epic branch (not develop). When all tickets are merged and the feature is verified, the epic branch is merged to develop as a single feature, which then follows the normal release flow.

flowchart LR
  develop["develop"] -->|branch| epic["epic branch<br/>(named after the epic)"]
  epic -->|branch| t1["PPL-NNNN/ticket (backend first)"]
  epic -->|branch| t2["PPL-MMMM/ticket (frontend)"]
  t1 -->|"small PR, reviewed"| epic
  t2 -->|"small PR, reviewed"| epic
  develop -.->|"rebase/merge regularly"| epic
  epic ==>|"one atomic PR when whole epic done"| develop
  • Ticket branches keep the PPL-NNNN/... naming and the PR review rules, but target the epic branch. Typically the backend ticket lands first, then the frontend branches off the updated epic branch.
  • Sub-PRs stay reviewable. Each ticket PR is small and reviewed on its own (and can use draft status until ready), so no one reviews 6,000 lines at once.
  • Copilot noise is handled in the sub-PRs: address its comments there so the eventual epic → develop PR is clean. Whether to action each Copilot comment is the engineer's discretion (see PR reviews).

CONFIRM — epic branch naming

The meeting agreed the branch is "named after the epic" but didn't fix the exact token. Proposed: PPL-<epicId>/<slug> for the epic branch, with ticket branches PPL-<ticketId>/<slug> cut from it. Confirm and lock this before wide rollout.

Testing

Preview environments still apply — opening a PR with the preview label spawns a preview (members, clinicians, backend) so QA can verify the feature against the epic branch. After the epic merges to develop, smoke-test on the release branch since it now interacts with everything else.

Bugs found during review become sub-tickets off the epic branch, so the main work can merge and fixes follow as their own small PRs.

Keeping it healthy

Long-lived branches risk a giant merge conflict at the end. Discipline to avoid that:

  • Sync continuously. Whenever a sub-branch is reviewed and merged into the epic branch, immediately update the epic branch against develop (rebase/merge) so conflicts are resolved in small increments, not all at once.
  • The epic lead owns keeping the epic branch up to date with develop.
  • Keep them short-lived. With a Plan in hand (see DPPD) most of the uncertainty is gone, so dive in and ship the epic rather than picking up side work.

Guardrails discussed (to be confirmed as we trial):

CONFIRM — limits & visibility

  • A WIP limit on the number of epic branches open at once (cap TBD).
  • A daily report in #tech listing open long-lived branches and how many days each has been open — for focus, not pressure.

These were agreed in principle but not yet implemented; confirm the cap and the report mechanism before relying on them.