Git Branching
PP Core commits its own work as it executes, and you decide how those commits land in your repository. The branching strategy controls whether work goes straight onto your current branch or is isolated on a dedicated branch per phase or per milestone.
Branching Strategies
Three strategies are available, configured under the git section of .planning/config.json:
| Strategy | Default | Description |
|---|---|---|
none | Yes | All work commits directly to whatever branch you are currently on. |
phase | No | A fresh branch is created at the start of each phase execution. |
milestone | No | A single branch holds every phase belonging to one milestone. |
The default, none, keeps things simple: PP Core never switches branches and you manage integration yourself. Choose phase when you want each phase to be independently reviewable and mergeable. Choose milestone when you would rather batch a whole milestone's worth of phases onto one branch and open a single pull request at the end.
Configuration Keys
All branching settings live in the git section:
| Key | Default | Description |
|---|---|---|
branching_strategy | "none" | Selects which of the three modes is active. |
base_branch | "main" | The integration branch that new branches are cut from and merged back into. |
phase_branch_template | "pp/phase-{phase}-{slug}" | Naming pattern for branches created in phase mode. |
milestone_branch_template | "pp/{milestone}-{slug}" | Naming pattern for branches created in milestone mode. |
create_tag | true | Whether to create a git tag when a milestone completes. |
quick_branch_template | null | Optional auto-branching pattern for /pp-quick. When null, quick tasks do not branch. |
A typical feature-branch setup looks like this:
{
"git": {
"branching_strategy": "phase",
"base_branch": "main",
"phase_branch_template": "pp/phase-{phase}-{slug}"
}
}
Branch Name Templates
Branch templates are filled in from the phase or milestone being worked on. The available variables are:
| Variable | Used in | Format |
|---|---|---|
{phase} | phase_branch_template only | Zero-padded number, e.g. 03. |
{slug} | Both templates | Lowercase and hyphenated, e.g. user-auth. |
{milestone} | milestone_branch_template only | Version string, e.g. v1.0. |
With the default phase template, executing phase 3 of an authentication feature produces a branch named pp/phase-03-user-auth. With the default milestone template, the v1.0 milestone of the same feature produces pp/v1.0-user-auth.
How Commits Are Made
PP Core makes atomic commits as it works, but where they land depends on the active strategy:
- none — commits go straight to your current branch. Nothing is created or switched.
- phase — a phase branch is cut from
base_branchat execution start, all of that phase's commits land there, and you merge it back when ready. - milestone — a milestone branch is created once, and every phase in that milestone commits onto it, so the whole milestone arrives as one integration unit.
Choosing a Strategy
Reach for none on solo projects or throwaway work where branch overhead adds nothing. Use phase when you want a clean, reviewable unit of work for each phase — this pairs naturally with a pull-request workflow, since each branch maps to one PR. Use milestone when phases are tightly coupled and only make sense reviewed together. In all cases, base_branch defines the trunk that work integrates into, so set it to main, develop, or whatever your team treats as the integration line.