Documentation pages

GUIDES

Conflicts

A conflict happens when a dotfile changed on this machine and on another machine since the last sync.

ONE FILE, TWO EDITS Without a terminal
The sync records the conflict, notifies you, and keeps the local file out of the push until you run tether resolve.↔

In a terminal

tether sync asks how to resolve each conflict:

  • Keep local version
  • Use remote version
  • Launch merge tool
  • Skip (decide later)

-y never picks a side. With -y, the sync skips the conflict.

Without a terminal

The daemon, and a sync from cron or ssh, do not ask. For each conflict, the sync:

  • records the conflict for tether resolve
  • sends a notification
  • keeps the local file out of the push until you resolve the conflict, so it does not overwrite the other machine's change

tether status counts the files with conflicts.

Resolve a conflict

Terminal
tether resolve           # every conflict
tether resolve .zshrc    # one file
  • A conflict on a file that still syncs stays until tether resolve. This includes a file that this machine ignores with tether ignore files
  • A conflict on a file that no dotfile entry covers any more is dropped

Settle conflicts without a question

Some apps rewrite a file on every machine, for example with timestamps or caches. Give that file a rule in config.toml, and Tether settles its conflicts on its own:

toml
[[profiles.dev.dotfiles]]
path = ".claude/plugins/known_marketplaces.json"
on_conflict = "local"   # or "remote"; the default is "prompt"

Machines on 1.11 and 1.12 drop on_conflict when they save the config. 1.13 keeps it.

Merge tool

"Launch merge tool" runs merge.command with merge.args. The default is opendiff on macOS and vimdiff on Linux. A machine without opendiff uses vimdiff when the synced tool is opendiff.

Tether runs only merge tools from a built-in list, such as vimdiff, nvim, meld, kdiff3 and p4merge. A synced config cannot make it run another command.

To use another tool on one machine, set it in ~/.tether/local.toml:

toml
[merge]
command = "vimdiff"
args = ["{local}", "{remote}", "{merged}"]   # the default when args is missing