Safe Conflict Resolution
When two devices edit the same path between syncs, Dropbear refuses to guess which version wins. Instead it keeps both, in plain sight, and waits for you. Nothing is lost, nothing is silently overwritten, and the merge — when there is one — is a human decision made with both files in hand.
That safety has a cost: conflicts are work. Dropbear will hand you a tidy pile of .conflict-* files and an honest report, but it will not resolve them for you, and a busy multi-device setup can accumulate them faster than you'd like.
How it works
When sync finds that another device changed a file you also changed (different hashes, no common ancestor in this device's last manifest), it does three things:
- Materializes the other device's bytes alongside your local copy as
<stem>.conflict-<otherDeviceID>-<UTC-ts><ext>. The original path keeps your local version untouched. - Flips the local row to
StatusConflictinstate.sqlite. - Omits that path from this device's next manifest and upload set. Neither version is published until you resolve the conflict.
Symlinks get the same treatment — the remote target string is written into a conflict-suffixed symlink. Directory collisions, multi-device disagreement, and entries missing a payload fall back to skip-with-warning rather than materializing a conflict file; you'll see them in sync output and in dropbear status.
What "safe" buys you
- No silent loss. Both versions are on disk, byte-for-byte, with the other device's
device_idand the UTC timestamp baked into the filename. You candiffthem, you can keep one, you can keep both, you can merge by hand. - No bucket-side guessing either. Because the conflicted device publishes neither version, no downstream device sees a half-resolved state. The conflict stays local to the device that detected it until a human acts.
- Reproducible. The conflict-file naming is deterministic.
dropbear statusparses the basenames back into(device-id, timestamp)pairs and lists them per path, so you can see at a glance what's pending where.
What it costs (the honest part)
Conflict resolution is manual labor. There is no dropbear resolve command yet — the workflow today is roughly: pick the version you want, overwrite the canonical path with it (or merge by hand), delete the .conflict-* siblings, and run sync again. That's three or four shell steps per conflicted path. If you've been offline on a laptop for a week and come back to forty conflicts, that's forty rounds of decision-making.
There are some sharp edges to know about:
- Multi-device disagreement (more than one other device has diverged from your local version) currently falls back to skip-with-warning rather than materializing N conflict files. You'll see the warning in
syncoutput but no.conflict-*copy will appear; the path stays conflicted until the other devices converge or you intervene directly against the bucket. - A conflicted path blocks publication of that single path, not the whole sync. Other files keep flowing. But the conflicted path stays unpublished from this device until resolved, which means other devices won't see your version of it until you act.
.conflict-*files are themselves tracked. They're regular files in the root. If you leave them lying around they get synced too, just under their conflict-suffixed names. Cleaning them up is part of resolution.- A
resolvecommand is on the wishlist — see the resolve-command idea — but until it ships, the touch + rm + sync dance is the workflow.
When this trade is right (and when it isn't)
Safe-by-default conflict handling is the right call for personal data you can't afford to lose: photos, notes, financial records, code you haven't pushed elsewhere. The labor cost is real but bounded, and the alternative (auto-merge or last-writer-wins) silently destroys data in exactly the case where you'd most regret it.
If your workload is high-frequency collaborative editing of the same files from multiple devices — a shared notes app, a multi-author document — you'll generate conflicts faster than you can resolve them, and Dropbear is the wrong tool. Use something with proper CRDTs or an operational-transform editor for that, and let Dropbear sync the output once you've reconciled.
See also
- conflict and tombstone in the glossary
dropbear status— the canonical view of what's currently pending