Your Git branching model in TOVIO¶
TOVIO doesn't ship a branching model — it ships a few composable primitives, and every Git branching model is just a particular arrangement of them. So you don't "switch to" GitHub Flow or Git Flow; you express the model you already use (or want) by declaring which lanes exist and what rules each one carries. This guide gives a copy-paste setup for each common model.
Built and tested; release evidence remains open
The offline core (commit, land, lane, stacks, tag) runs today. Lane protection,
proposals/review, and sync are built and pass their hermetic --features tls test suite.
Production binaries passed the distinct-Docker-host exercise under a real operator CA;
public-release, broader HA/load, hosted-parity, and external evidence remain Phase 5 gates.
There is no separate tovio merge verb: tovio land <source> --into <target> is how one lane is
folded into another, so every "promote forward" step below is a land.
The four things you decide¶
Any workflow is just answers to these:
- Which lanes exist —
main,env/*,release/*,feature/*? Create any withtovio lane <name>(the new lane points at the current lane's tip). - Which are protected, and with what gate — declared as
[[protected_branch]]blocks in the policy manifest (lane protection):require_conflict_free,required_checks,write_policy, andrequire_review.tovio policy protect <pattern>writes the review half of the block for you (--require-review,--min-approvals,--reviewers/--reviewer,--required-checks) and always setsrequire_conflict_free = true. It has no flag forwrite_policy; a lane that declares none falls back to the effective pathwrite_policyfromtovio policy set. - Who may land / read where — path policies and each lane's
write_policy. - Your promote / backport convention — you land forward (
landonto the next target); stablechg:ids make it traceable.
Nothing here is code — it's configuration + convention, versioned in the repo. The building blocks in one line:
you live in a change, a lane is a landing target,
land puts a change — or a whole lane — on a lane, and [[protected_branch]] encodes "this lane is special."
Which model do you use?¶
| Coming from… | Jump to | One-line TOVIO shape |
|---|---|---|
| Trunk-based development | below | Protect main; land stacked changes continuously |
| GitHub Flow | below | Protect main; short lane/stack → proposal → land |
| GitLab Flow (env branches) | below | Protected env/*; promote by landing forward |
| Git Flow | below | Drop develop; feature→stacks, release/* + hotfix backports |
| Release trains | below | Cut release/x.y from trunk; backport the same chg: |
| Forking workflow | below | Scoped access usually replaces the fork |
Trunk-based development (the default)¶
TOVIO's native idiom. Everyone lands onto main continuously; anything half-done hides behind a feature
flag. Least ceremony, least integration debt.
[[protected_branch]]
pattern = "main"
require_conflict_free = true
required_checks = ["build-check", "semantic-check"]
# + `tovio policy protect main --require-review` for a team repo (an approved proposal to land)
$ tovio commit -m "…" # stack changes as you go
$ tovio change propose --remote forge.example.com:8443 # open the current change for review on the Forge
$ tovio land my-lane --into main # land straight onto trunk; the stack cascades
Who may approve is part of the lane's protection (--reviewers / --reviewer on tovio policy protect),
not an argument to propose.
Feature branches mostly disappear — replaced by stacked changes. Use a shared feature branch only when a feature must stay off trunk as a unit.
GitHub Flow¶
main is always deployable; each unit of work is a short-lived branch → Pull Request → merge → deploy.
- PR → proposal.
tovio change propose chg:xxx --remote <host:port>. - Branch protection → the same protected-
mainblock as trunk-based; eligible reviewers live there. - Merge → land. After approval + checks,
tovio land my-lane --into main.
# a short stack (or a small feature branch), then:
$ tovio change propose chg:xxx --remote forge.example.com:8443
# …review + required checks pass…
$ tovio land my-lane --into main
You rarely need a literal lane per unit of work — a stack does it — but if your team likes the lane,
create feature/x, land onto it, and promote as in feature branches.
GitLab Flow (environment branches)¶
Maps the cleanest. main → env/staging → env/prod, each a protected lane; you promote forward
and tag at prod.
[[protected_branch]]
pattern = "main"
require_conflict_free = true
required_checks = ["build-check"]
[[protected_branch]]
pattern = "env/*"
require_conflict_free = true
required_checks = ["build-check", "smoke-tests"]
write_policy = "role=release-manager" # only release managers promote
$ tovio land my-lane --into main # features land on trunk first
$ tovio land main --into env/staging # promote the vetted set forward
# …verify on staging…
$ tovio land env/staging --into env/prod # promote forward again
$ tovio switch env/prod # `tag` defaults to the CURRENT lane's tip
$ tovio tag v2.5.0
A broken promotion can't advance — the protected env/prod gate refuses a non-buildable or unreviewed set.
Git Flow¶
The develop + feature/* + release/* + hotfix/* + main model. In TOVIO the shape survives; the
mechanics dissolve:
- Drop
develop. Trunk + stacked changes already give you the integration line — one fewer permanent lane. feature/*→ stacked changes, or a shared feature branch for a whole team.release/*→ a long-lived protected lane cut from trunk; receives only backports.hotfix/*→ one change landed to prod, then backported by landing the samechg:id onto each release line andmain— resolve the conflict once, it re-applies.- Tags immutable.
[[protected_branch]]
pattern = "main"
require_conflict_free = true
required_checks = ["build-check", "semantic-check"]
[[protected_branch]]
pattern = "release/*"
require_conflict_free = true
required_checks = ["build-check"]
write_policy = "role=maintainer"
# hotfix authored off prod state:
$ tovio commit -m "fix: clamp dose overflow (SEC-114)" # → chg:hot
$ tovio land my-lane --into env/prod # ship to prod
$ tovio land my-lane --into release/2.4 # backport — SAME chg:hot; resolve once…
$ tovio land my-lane --into main # …and it re-applies here
Git Flow in Git: hotfix branch → merge to main → cherry-pick to each release/develop, re-resolving the
same conflict every time. TOVIO: one change id everywhere (traceable), conflict resolved once.
Release trains / long-lived release lines¶
Cut a release line from trunk, stabilize it with backports, tag each release.
$ tovio switch main # a new lane points at the CURRENT tip — stand where you want to cut
$ tovio lane release/2.5 # cut the release line from trunk
# declare a release/* protected_branch block (above), then only backports land here:
$ tovio land my-lane --into release/2.5 # same chg: id also lands on main
$ tovio switch release/2.5 # `tag` defaults to the CURRENT lane's tip
$ tovio tag v2.5.0
The tax of long-lived release lines in Git — re-resolving the same backport conflict on every line — collapses to a single resolution that propagates (the conflict algebra).
Forking (external contributors)¶
Two angles:
- You often don't need a fork. Because access is cryptographic and path-scoped, "fork so you can't touch protected stuff" is replaced by granting a contributor (or their agent) a capability token / access scoped to their paths. They clone, work, and propose directly — no fork to maintain.
- When you do want isolation, a fork is just a clone pointing at its own Forge/relay; contributions come back as a proposal, or a cross-repo meta-change for coordinated multi-repo work.
Build your own house workflow¶
Compose the primitives:
tovio lane <name>the lanes your process needs.- Add a
[[protected_branch]]block per special lane (tovio policy protect <pattern> …) — strict onmain/release, light or none on throwaway lines. - Add path policies for who lands/reads where (and per-team secrets by path).
- Write down the promote/backport convention (land forward; same
chg:for backports). - (Optional) enforce house rules with
required_checksand pre-land plugins (e.g. "every land needs a signed CHANGELOG entry").
Why these cost less than in Git¶
- CRDT refs → no "rejected / diverged history"; concurrent promotions and lands converge, and a real content fork becomes a first-class conflict object, not a wedged push.
- Stable change IDs → backports/promotions are traceable (the same
chg:everywhere), and resolve-once propagation kills the biggest tax of long-lived release/env lanes. - Auto-rebase cascade → stacked and feature work re-parents itself on land; no manual rebase chains.
- The gate is enforced client-side and at the relay → lane protection can't be bypassed by a direct push.
- It's all config → your workflow is
protected_branchblocks + policies + a convention, versioned in the repo.
The honest caveat
Long-lived lanes still accrue integration debt — TOVIO lowers it, it doesn't repeal it. The idiom nudges toward trunk + feature flags + short-lived lanes + land forward; reach for the heavier models when a feature or release genuinely needs isolation.
Where to go next¶
- A team on one feature (shared feature branches) — the multi-dev, isolated-then-released case in depth.
- Lane protection — every lever in the
[[protected_branch]]block. - Branching workflows — the day-to-day loop as diagrams.
- Coming from Git — the verb-by-verb translation.
- Checking in: change vs lane — why
commitandlandare two verbs.
Last reviewed September 9, 2026
Suggest an improvement to this page Not for security reports — see disclosure