Branches & Merging
Swarmfile branches follow the Perforce-streams model, not git branches. A branch is a full working line over the project's content-addressed storage, not a lightweight pointer into a shared history graph - but because storage blocks are content-addressed and shared, forking a branch doesn't copy any file data. Only the metadata diverges, and only once you actually change something. Fork a 4TB project and the fork costs you nothing until you start editing.
Branches are project-scoped#
A branch applies to an entire project, not a folder inside it. You don't branch a subdirectory and leave the rest of the project on main - every mount of the project works one branch, in full, independently of every other mount. This keeps the model simple: there's never a question of which branch a given folder is "really" on.
Creating, listing, and archiving#
swarmfile branch create look-dev-warm --from main
swarmfile branch list
swarmfile branch archive look-dev-warm
branch create forks a new branch, defaulting to a fork from main if you omit --from. branch list shows the active branches on the project. branch archive soft-archives a branch you're done with - main itself can't be archived.
All three operations are also available from:
- The web dashboard - the Commits view lists, creates, and archives branches, and can trigger a merge.
- The tray - a Branches panel does the same, applied immediately, with no restart required for list, create, or archive.
- The CLI -
swarmfile branch {list,create,switch,archive},swarmfile tag {list,create,delete}, andswarmfile merge.
A typical use: fork a branch to try a look-dev variant or a design option without duplicating the whole project, then merge it back if it works out, or archive it if it doesn't.
Branching from a past commit, or a tag#
By default, branch create forks the source branch as it is right now. Give it a commit number or a tag instead, and it forks the source exactly as it stood at that point - every file carrying the content it had then, in one call, instead of forking at head and then rolling the fork back with checkout:
swarmfile branch create recover --from-commit 482
swarmfile branch create recover --from-tag v1.0
--from is optional with either: the targeted commit or tag already names which branch it lived on. If you give --from anyway and it disagrees with that branch, the command refuses rather than silently picking one.
This is the primitive a headless or unattended machine - a render farm node, a CI runner - uses to pin itself to an exact historical state with a single command and no tray or browser interaction:
swarmfile commit -m "submit render job 482"
swarmfile tag create v1.0
swarmfile branch create render-fix --from-tag v1.0
A tag is a project-scoped, immutable name for a commit - nothing more. There's no "move a tag" command; to repoint a name, delete it and create it again:
swarmfile tag list
swarmfile tag create v1.0
swarmfile tag delete v1.0
tag create defaults to the branch's CURRENT head - exactly what the commit above just produced, no need to look up its commit number first. Give it --at-seq <n> explicitly to tag an older commit instead of the head:
swarmfile tag create v0.9 --at-seq 482
The web dashboard's Commits view offers the same two actions per commit row - "Branch from here" and "Tag" - plus a tag picker next to the branch selector; the tray's Branches panel has a source-type picker (branch / commit number / tag) on its create form, and its own Tags panel for list/create/delete.
Switching branches#
swarmfile branch switch look-dev-warm
swarmfile branch switch # omit the name to switch back to main
Switching branches is hot - no engine restart, no interruption to the mount. The first time a machine visits a branch, switching to it pays a one-time full sync (proportional to that branch's size); a repeat visit to a branch it's already synced is a fast incremental catch-up. Switching is refused while a changelist is open - submit or cancel it first, so staged work is never silently discarded or reattached to the wrong branch.
List, create, and archive don't touch the running mount and take effect immediately, same as switch now does.
Merging#
swarmfile merge
swarmfile merge --record-conflicts
merge performs a whole-file three-way merge of your mount's current branch back into the branch it was forked from - its parent. That's usually main, but a branch forked from a non-main branch merges back into that branch. The direction is implicit either way: there's no target flag to set, because a branch already knows its own parent. Because these are binary assets, there's no line-level merge to fall back on - merging is winner-take-all per file, with conflict detection when the same file changed on both sides since the fork point. By default, conflicts are surfaced as a list; --record-conflicts instead records conflict rows you can resolve interactively, one file at a time, rather than just being told a file collided.
Merge Requests#
swarmfile merge lands a branch immediately - useful when you're merging your own work and you're confident it's ready. When you want someone else to look at a branch before it lands, open a Merge Request instead, from the web dashboard's Merge Requests tab: pick the branch, give it a title, and it's posted for review.
A Merge Request shows reviewers exactly what would change - the same list of added, modified, deleted, and renamed files a direct merge would land, computed fresh every time the page loads, so it's never a stale snapshot. Reviewers leave an Approve or Request changes verdict (optionally with a note); only the latest verdict from each reviewer counts, so changing your mind is just casting a new one. Merge only becomes available once at least one reviewer has approved and nobody's latest verdict is "request changes" - there's no configurable approval count or required-reviewer list in this version, just that one rule.
Clicking Merge does exactly what swarmfile merge does - same conflict detection, same all-or-nothing landing, same optional "record conflicts for resolution" fallback if the branch drifted since anyone last looked at the diff. A Merge Request that's approved but hits a conflict on click still 409s, same as a direct merge would; nothing lands until the branch is fixed.
Any project member can open, review, and merge a Merge Request - it isn't admin-gated, unlike RFIs. Merge Requests are a web-dashboard feature in this version; there's no CLI equivalent yet (swarmfile merge remains the direct path).
A different kind of conflict#
Branch merges aren't the only place conflicts happen - and the other kind is more common. If you and a teammate both edit the same file on the same branch while one of you was offline, Swarmfile catches it when the offline edit tries to land: the change was made against a base version that's no longer current. Rather than silently keeping both copies and leaving you to notice, it records a conflict and refuses further writes to that file until it's resolved. That's why an application may report a plain I/O error on the file, and why swarmfile conflicts exists - a filesystem has no way to say "someone else changed this too," so that command is where the reason lives.
Resolving is a deliberate choice between up to four outcomes, offered as a banner in the web dashboard and a modal in the tray (both open the same picker):
- Keep mine - your offline version becomes the current head; the other edit is superseded.
- Keep theirs - drop your offline edit and keep the version already on the hub.
- Keep both - the hub keeps the current head, and your version lands alongside it as a sibling file with a conflict suffix, so nothing is lost and you reconcile them by hand.
- Try an automatic merge - for file types with a registered merge tool (currently plain text and common source/config formats), click "Try automatic merge" and Swarmfile runs a three-way line merge of your edit against theirs. If it succeeds cleanly, a fourth choice appears - the merged result - for you to review and accept instead of picking a side. If the file type isn't supported, or both edits touched the same lines, the attempt just fails harmlessly and you're left with the three choices above.
Like branch merging, whole-file is always available as a fallback here - a binary asset never has a line-level merge to fall back on, which is why the first three choices always work regardless of file type. Until you resolve the conflict, the file stays read-only; once you do, writes resume with no restart.
Where to go next#
- Version Control covers changesets, checkout, and per-file history - the model branches sit on top of.
- CLI: swarmfile has the full command reference for
branchandmerge.