Skip to content

Resolve conflicts

In TOVIO a conflict is stored data, not a blocking error. When two changes can't be merged automatically, the merge completes and the conflict is saved as an object you resolve when you're ready. Your repository stays fully operational with open conflicts: you can keep editing, committing, switching, and stacking on top. Think of a conflict like a type error you can see and work around — not a crash that halts everything.

A stored conflict is success, not failure

A land that stores conflicts exits 0 and reads as "nothing is blocked." It will never show up as a fatal:-style error. The only hard limit: a change with unresolved conflicts can't land onto a protected lane — because shared code must stay buildable.

Most of this surface is implemented

tovio resolve (with all its flags), tovio conflicts (the list), the stored-conflict object, and the protected-lane land gate are implemented in the current source tree — the sound-merge engine, with rerere replay, is wired into land, rebase, switch, and resolve. Conflicts are addressed by path, not by a conflict id. Three things on this page are still ahead: a standalone tovio merge verb (integration is tovio land), the tovio conflicts show / reopen subcommands, and the tovio cx short alias. Where those appear below, read them as the designed surface. No generally available package has been published.

flowchart LR
    M["tovio land"] --> S["Stored conflicts<br/>(one per path)"] --> R["tovio resolve<br/>(kind-directed)"] --> D([✓ resolved]) --> L["tovio land"]

More diagrams for every kind, the land gate, and rerere replay: Conflict workflows.

What a stored conflict looks like

A land that can't auto-merge a path completes and tells you plainly:

$ tovio land feature/cgm-sync --into main
✓ landed `feature/cgm-sync` into `main` with 3 conflict(s)  blake3:fd9764d8b6…
    ⚠ content       src/integrations/cgm/dexcom.ts
    ⚠ content       src/integrations/cgm/types.ts
    ⚠ content       tests/integrations/cgm.test.ts

  nothing is blocked — the conflicts are stored as data.
  resolve them:   tovio resolve
  list them:      tovio status --conflicts

Open conflicts also surface in tovio status, so you never lose track of them.

List open conflicts

$ tovio conflicts
1 open conflict(s):
  src/integrations/cgm/dexcom.ts  (content · unresolved)
  → Next: `tovio resolve <path>` to resolve a conflict (or `--ours` / `--theirs`)

Each row is the conflicted path, its kind, and its status. The command exits 0 — it reads as attention, never as an error. To see why a path conflicted — the merge base, both sides, and which decision each file got — use the merge lens of tovio explain (tovio explain merge <lane> --into main), or tovio explain rerere <path> for whether a recorded resolution would replay.

Designed inspection subcommands

The CLI specification also designs tovio conflicts show for one conflict's kind, both sides, and base; it is not implemented yet, and neither is the tovio cx short alias.

Resolve a conflict

With no strategy flag, resolve walks each open conflict — or one, if you name its path — in a console-native hand-merge: a unified ours-vs-theirs diff per region, and a per-region choice (keep a side, take both, hand-merge inline). No conflict markers ever touch your files and no external editor opens:

$ tovio resolve                                   # walk every open conflict
$ tovio resolve src/integrations/cgm/dexcom.ts    # just this one

For a quick, non-interactive decision on a content conflict, pick a side:

$ tovio resolve src/integrations/cgm/dexcom.ts --ours
$ tovio resolve src/integrations/cgm/dexcom.ts --theirs
$ tovio resolve src/integrations/cgm/dexcom.ts --base
✓ Resolved — kept ours of `src/integrations/cgm/dexcom.ts`  blake3:a7659add14…
  All conflicts resolved · undo with `tovio undo`

If you merged the file by hand (or in a merge editor), record the bytes on disk as the resolution with --working-tree. --ai asks the configured resolver plugin to propose a resolution — with no resolver bound, it declines. At most one strategy flag per call.

Conflicts come in kinds

resolve does the right thing for each kind — a text merge isn't always the answer:

Kind What it means How you resolve it
content Both sides edited overlapping lines Region-by-region merge, --ours / --theirs / --base, or --working-tree
add/add Both sides added the same path with different content Same choices as a content conflict
delete/modify One side deleted a file the other edited A keep-or-delete choice: --keep or --delete — not a text merge
rename/edit One side renamed, the other edited Usually auto-merged; only surfaces if edits overlap
rename/rename Both sides renamed to different paths Pick the path: --rename-to <path>
semantic A change broke references another change relied on Advisory — a warning listing the affected changes; doesn't block unless a protected lane requires the semantic check
$ tovio resolve src/integrations/cgm/legacy.ts --keep
$ tovio resolve src/integrations/cgm/dexcom-client.ts --rename-to src/integrations/cgm/client.ts

Record why

A resolution is a decision worth remembering. --why "<one or two sentences>" attaches an attested rationale to the resolving commit (optionally with --decision, --rejected "<option> :: <reason>", --dead-end, --confidence low|medium|high, --ref), and tovio log --why shows it later. For a policy-protected path the rationale is sealed automatically.

These flags — and --region — ride a one-shot resolution, so they require a path and a strategy flag. Authoring a rationale from inside the interactive walk is still ahead; tovio resolve --why "…" on its own is a usage error naming the strategy flags it needs.

A resolution propagates — resolve once

When you resolve a conflict, the resolution is recorded and replayed wherever the same conflict appears again — you don't re-resolve the identical conflict in three different changes. Resolve once; TOVIO carries it across. Region choices made with --region replay on a later land alongside the whole-file resolution.

It also persists across history rewriting. A resolution recorded before you amend, rebase, split, or absorb still applies afterward — rewriting your history doesn't make a resolved conflict come back, and it won't reappear on your next sync. tovio explain rerere shows, per open conflict, whether a recorded resolution matches and would replay — and if not, exactly why.

Resolution reuse is implemented

Both halves of the behavior above are implemented in source: resolution reuse for the identical conflict, and the rerere replay that carries a resolution across every context and through a later land and history rewriting. It is part of the sound-merge engine wired into resolve and land, but is not a claim that a generally available binary has been published.

Reopen a resolved conflict

Changed your mind, or resolved one wrong? The resolution is op-logged, so tovio undo reverses it and the conflict is open again.

Designed reopen subcommand

The CLI specification also designs tovio conflicts reopen for reopening a specific resolved conflict without unwinding the op-log; it is not implemented yet.

The one hard limit: protected lanes

A conflict never blocks your in-flight work, but it does block landing onto a protected lane (main, release). Those lanes are guaranteed buildable, and a file holding both sides of a conflict won't compile. So tovio land onto a protected lane refuses with TVO-CONFLICT-003 until the change is conflict-free:

✗ Cannot land: 1 unresolved conflict(s)

  Landing `my-lane` into protected `main` leaves 1 unresolved conflict(s):
    content       src/integrations/cgm/dexcom.ts
  …

Check landability any time with tovio change health <change-id> — it reports whether a change is conflict-free, how stale it is, and whether it is ready to land, without changing anything.

Pulling a teammate's conflicted change is gated too

Within your own stack, conflicts are non-blocking. But TOVIO won't silently materialize a teammate's unresolved conflict into your working tree and break your build. That cross-developer boundary — and the --isolate option to build against the last-known-clean version — lives in the collaboration guides.

Where to go next

Last reviewed September 9, 2026

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