Browse docs
Docs / Guides / Version Control
View as Markdown

Version Control

Swarmfile versions every file the way a VCS versions code - except the files are whole binaries (video masters, CAD assemblies, GIS rasters) instead of text. There's no meaningful line-level diff for a 200GB ProRes file or a Revit model, so the model is built around whole-file commits and whole-file history instead of line hunks. If you're used to git or Perforce, the mental model carries over; the mechanics underneath don't.

Changesets#

A changeset is a named, revertable commit that can span multiple files, ordered in a DAG the same way git commits are - you can always roll every file in it back to its pre-commit state as one unit. A revert or point-in-time restore (checkout) covering more than the hub's interactive limit (about 5,000 entries) runs as a durable background job: the CLI waits for it by default (Ctrl-C or --no-wait detaches with exit 3, followed with swarmfile op status), and the result appears in the log once it lands. Whether the underlying saves actually land atomically (all at once, invisible until they do) depends on which of the two modes below produced it.

Swarmfile supports two ways of producing changesets, and you pick the one that matches how you work.

Mode A: auto-landed (default)#

By default, your saves land as commits automatically as you work, and immediately: each save is live on HEAD the moment it uploads, visible to teammates right away - it isn't held back waiting on anything else. What Swarmfile groups is the changeset those saves get filed under: consecutive saves are batched into one open changeset while you're actively working, and that changeset closes and commits once saves go idle for changeset_idle_secs (default 5 minutes, configurable via SWARMFILE_CHANGESET_IDLE_SECS or the config file). A burst of edits becomes one named, revertable commit; the next burst after a break becomes another. You don't open or close anything yourself - this is the lower-friction mode and it's what most people want most of the time. One exception: a save whose bytes are identical to the version already on HEAD files nothing - there's no change to commit, so it doesn't create a new version (an app that rewrites a file unchanged on close therefore can't spam history).

swarmfile commit -m "Color grade pass 2 on interview B-roll"

commit opens and submits a changeset in a single step - the Mode A pattern, useful when you want to attach a specific message to a specific save rather than relying on the automatic one.

Mode B: staged, explicit submit#

For work you want to land as one deliberate, reviewed unit - a multi-file asset swap, a batch of renders that only make sense together - open a changelist, stage saves into it, and submit (or cancel) the whole thing as one atomic transaction. It's the same shape as a git index: nothing is visible to teammates until you submit, unlike Mode A where each save is already live the moment it happens.

swarmfile changelist open -m "Swap all Act 2 plates to final grade"
# ...work happens, saves are staged into the open changelist...
swarmfile changelist status
swarmfile changelist submit

changelist submit -m "message" sends the commit message at submit time (git-style); without -m the group's open-time label is kept, and a group with neither is committed without a message. Submitting checks write access to every file in the changelist at that moment, so a save staged before a permission change doesn't bypass it; a refused submit leaves the changelist staged, nothing lost.

If you change your mind partway through, swarmfile changelist cancel discards the staged changes instead of submitting them.

On the Desktop App, the Changes tab shows the same work with a git-style commit box: type a summary (and an optional description) and press Publish. The message is required, just like a git commit, and is sent with the publish. A group's open-time label, if it has one, prefills the summary. The switcher's per-row publish (acting on another open group) sends no message - that group keeps its label, or is committed without a message when it has none.

Multiple changelists at once#

You're not limited to one open changelist. Open a second while the first is still open, and each save stages into whichever one is current - the same idea as Perforce's -c flag:

swarmfile changelist open -m "Swap all Act 2 plates to final grade"
swarmfile changelist open -m "Quick fix: wrong LUT on shot 12"
# saves now stage into the second changelist, since it's current
swarmfile changelist list
#   #a1b2c3d4 "Swap all Act 2 plates to final grade" - 6 file(s) staged
# * #e5f6a7b8 "Quick fix: wrong LUT on shot 12" - 1 file(s) staged
swarmfile changelist current a1b2c3d4

changelist list shows every open changelist with a * marking which one is current; changelist current <id> switches. This lets you juggle two unrelated in-flight edits without submitting one to start the next - no need to interrupt a large staged batch just to make an unrelated quick fix.

If a file was staged into the wrong changelist, move it without unstaging and restaging by hand:

swarmfile changelist reopen "Renders/Act2/shot12.mov" --to e5f6a7b8
swarmfile changelist reopen --to e5f6a7b8 --from a1b2c3d4

The first form moves a single staged file; the second (no path) moves every staged file from one changelist to another in one atomic step. Either can target a specific changelist without switching to it first - submit/cancel also both accept --id <changeset> for the same reason.

Setting work aside#

If you need to leave the branch or project but aren't ready to submit or cancel, park the work instead - it's set aside and kept alive on the hub, then restored when you come back to that scope or explicitly:

swarmfile changelist park       # set every open changelist aside
swarmfile changelist parked     # list parked work, with age and file count
swarmfile changelist resume     # restore parked work for this branch
swarmfile changelist discard    # abandon it (asks first; --yes skips)

Parked work is a set, not a stack: resume restores all parked work for the branch, and discard abandons all of it (or one, with --changeset <id>). A branch or workspace switch into a scope with staged work offers "Park for later", which does the same thing before the scope flips; the Desktop App's Parked changes panel lists, resumes, and discards the same work.

If you're coming from git, swarmfile stash maps here: stash → park, stash pop → resume, stash list → parked, stash drop → discard.

Viewing history#

swarmfile changesets list shows the commit log, newest first. swarmfile log gives you the same history as a compact colored feed, closer to git log --oneline, when you just want a quick scan.

Checkout and restore#

swarmfile restore restores a scope to how it looked at a past commit - the whole project, a folder, or a single entry:

swarmfile restore 482 --path "Renders/Act2/final.mov"
swarmfile restore HEAD~3

The commit can be a number (#N from swarmfile log), HEAD, HEAD~N, a branch, a tag, a changeset id, or a 64-hex commit hash; a prefix (seq:/head:/branch:/tag:/changeset:/hash:) forces which kind is meant. swarmfile switch <branch> is the equivalent for changing which branch the mount works on. Both are the preferred, explicit commands; swarmfile checkout still exists as a git-habit shim that overloads the two the way git checkout does - a branch name switches, a commit number/HEAD/HEAD~N restores, and the checkout --at-seq <N> form still works - but switch/restore say exactly which one you mean.

This doesn't rewrite or destroy history - it creates a new commit that matches the old state and adds it to the log. If the restore turns out to be wrong, you can restore again to undo it; nothing is ever permanently lost by restoring.

Trash and per-file rollback#

Separate from the changeset system, every entry also has its own lightweight history: a per-user trash for soft-deleted files with a configurable retention window, and point-in-time rollback for individual files. It's simpler than a changeset - no multi-file atomicity, just "what did this one file look like at this timestamp." See Trash, History & Rollback for the full picture.

Where to go next#

  • Branches & Merging covers forking a branch to isolate risky work and merging it back.
  • CLI: swarmfile has the full command reference for commit, changelist, changesets, log, switch, and restore.