Skip to content

Versioning, the Safety Net

Chapter 4 ended with a delete that left nothing behind. File versioning is the setting that changes that ending: when a file in the folder is replaced or deleted, the device keeps the old copy in a hidden folder named .stversions instead of destroying it.

Syncthing offers several versioning schemes; the one run here is the simplest, trash can — old copies filed under their original names, kept (as configured in the lab) indefinitely. The lab switches it on for the gazette folder on both devices, live, by editing the folder's configuration through the API:

$ curl -s -X PUT -H "X-API-Key: $KEY" http://127.0.0.1:8395/rest/config/folders/gazette -d @gaz-b2.json
[HTTP 200]

and reads it back to be sure:

{
  "id": "gazette",
  "type": "sendreceive",
  "versioning": "trashcan",
  "cleanoutDays": "0"
}

cleanoutDays: "0" is the lab's choice and means never clean out automatically — worth noticing, because the other choice, a number of days, is how versioning stays a safety net instead of a second, slower disk-full.

The overwrite that didn't destroy

Willow replaces the draft with the revised text. Juniper pulls the new version — and this time, the copy it replaced is still on its disk:

$ find share-b/.stversions -type f
share-b/.stversions/issue-12-draft.md

$ cat share-b/.stversions/issue-12-draft.md
# The Riverbend Gazette - Issue 12 (draft)
…
## Community orchard day
…

That is the previous generation of the draft — the one with the orchard paragraph — intact under its original name. Then willow changes the draft again, juniper pulls that too, and the archive is worth a second look:

$ find share-b/.stversions -type f
share-b/.stversions/issue-12-draft.md

Still one file — and it now holds the revised draft, the generation just replaced. In this version of Syncthing (1.27.2, as captured), the trash can keeps one archived copy per file, the latest one replaced; a third change would have filed the third generation over the second. If your habit is many small edits and you want several generations back, that is what the other schemes — staggered keeps timestamped copies on a thinning schedule — exist for; they are named here and in the criteria, and their behaviour is documented- only in this guide.

Whose copies get kept

Notice where the archive appeared: on juniper, the device whose copy was replaced by an incoming change. On willow, where the edits were actually made:

$ ls share-a/.stversions
ls: cannot access 'share-a/.stversions': No such file or directory

Nothing. Versioning, as captured here, catches what sync does to a device — a file overwritten or deleted by a change arriving from elsewhere — not what you do to your own files with your own editor. That placement is arguably the right one (your own editor and your own backups are your side of the fence), but learn it now rather than after: a file you overwrite on the only device where you edit has no Syncthing safety net at all.

The delete, retried

Same delete as chapter 4 — the events list, removed on willow — with versioning on:

$ find share-b/.stversions -type f
share-b/.stversions/issue-12-draft.md
share-b/.stversions/events-list.txt

Juniper's copy of the file was deleted from the folder, as the mirror demands, and filed in .stversions in the same motion. Recovery is deliberately unmagical: it is a file, so you copy it back. On juniper, under a new name so the restore is visible as an act, not an accident:

$ cp share-b/.stversions/events-list.txt share-b/events-list-restored.txt

The restored file is an ordinary new file, so it syncs to willow like one — and the hashes close the loop, against the pristine fixture the lab started from:

$ sha256sum fixtures/events-list.txt share-b/events-list-restored.txt share-a/events-list-restored.txt
acb3531ab279d3980d1d2901363923da7d45f242aceb9c94e2fa54c631c04651  fixtures/events-list.txt
acb3531ab279d3980d1d2901363923da7d45f242aceb9c94e2fa54c631c04651  share-b/events-list-restored.txt
acb3531ab279d3980d1d2901363923da7d45f242aceb9c94e2fa54c631c04651  share-a/events-list-restored.txt

The file that was deleted on one continent of the setup is back on both, byte for byte.

Check: the shape of the promise. Versioning on a folder, one device deletes a synced file, and the surviving device should hold .stversions/<filename> with the old contents. If it doesn't, the usual reason is the one this chapter demonstrated on willow: you are looking on the device that made the change.