Skip to content

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:

  1. Which lanes exist — main, env/*, release/*, feature/*? Create any with tovio lane <name> (the new lane points at the current lane's tip).
  2. 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, and require_review. tovio policy protect <pattern> writes the review half of the block for you (--require-review, --min-approvals, --reviewers / --reviewer, --required-checks) and always sets require_conflict_free = true. It has no flag for write_policy; a lane that declares none falls back to the effective path write_policy from tovio policy set.
  3. Who may land / read where — path policies and each lane's write_policy.
  4. Your promote / backport convention — you land forward (land onto the next target); stable chg: 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-main block 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 same chg: id onto each release line and main — 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:

  1. tovio lane <name> the lanes your process needs.
  2. Add a [[protected_branch]] block per special lane (tovio policy protect <pattern> …) — strict on main/release, light or none on throwaway lines.
  3. Add path policies for who lands/reads where (and per-team secrets by path).
  4. Write down the promote/backport convention (land forward; same chg: for backports).
  5. (Optional) enforce house rules with required_checks and 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_branch blocks + 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

Last reviewed September 9, 2026

Suggest an improvement to this page Not for security reports — see disclosure