Core concepts
Fabric keeps everything good about Git (changes, review, a single source of truth) while removing the foot-guns: force-pushes, rebase hell, merge conflicts, and lost work. The difference comes down to one idea: the canonical store is a single append-only operation log, not a chain of commits you can rewrite.
The append-only operation log
Every edit is one operation: an entry appended to a single log. The log only ever grows in one direction: forward, at the end. That end is called the frontier, and it’s the only place you can write.
Two things follow, and they’re the whole model:
- You can only work at the end. Every change forks from the current frontier
and appends new operations onto it. You never edit, reorder, or delete an
operation that’s already in the log. If you’d normally rebase or amend, you
just append more operations instead, so there is no
rebase, no--force, and no history rewrite. - The full history stays, and stays readable. Because nothing is ever overwritten, the entire past is still there. You can replay the log up to any earlier point and see exactly how the repo looked then. But that’s read-only: you can view any point in the past, and you can only write at the frontier. (See Time-travel.)
A useful picture: a ledger you can only ever add the next line to. Every line above stays, exactly as written, and you read it freely, but you only ever write at the bottom, and you can’t go back and edit a page.
Because nothing is rewritten, nothing gets lost: there are no detached commits to drop and no force-push to overwrite a teammate’s work.
How merging works
Merging still happens: combining concurrent work is the core job of any version-control system. What changes is how: Fabric merges at the operation level, automatically and continuously, instead of stopping to make you resolve a conflict by hand.
When two people (or an agent) edit the same file at the same time, their edits are operations that converge automatically into a single consistent state. The key shift is where a conflict lives:
- Conflicts never land in your code. You never see
<<<<<<<,=======, or>>>>>>>written into a file, and editing never halts with a “merge failed: fix it by hand” error. Your working files always have one well-defined state. - A real conflict still exists, as a separate, tracked thing. Conflicts don’t disappear; they move out of your source and become their own reviewable item attached to the change. When two edits are genuinely incompatible, Fabric surfaces that conflict on its own, with full context, so you resolve it deliberately during review, instead of finding garbage spliced into a file and untangling markers.
- Review owns semantics. Automatic convergence guarantees a consistent file, not a correct one. Two people editing the same function can both land cleanly yet still produce combined logic that needs a human’s eye. That judgment lives in propose → review → accept.
Merging and conflicts still exist in Fabric. It takes the conflict out of your code and turns it into a separate thing you review, and it moves the part that actually needs human judgment (“is the combined result correct?”) into review.
Review and approval
A change can’t reach the trunk on its own. After you propose it, it goes
through review, and it must be approved before it can be accepted. Approval
is a deliberate sign-off by a reviewer, not something the change does
automatically and, as a rule, not something you do to your own change. More than
one approval is welcome. This is what keeps unreviewed or half-finished work from
ever landing on a trunk others build on.
Mapping from Git
| Git | Fabric | The difference that matters |
|---|---|---|
| branch | change | An isolated op-set forked from a frontier, not a movable ref. |
main | trunk | Trunks are per-subtree, not one global head. |
| commit | op | Append-only and content-addressed; per-edit, not per-snapshot. |
git push | fabric push | Appends your tree to the change as ops. It does not touch trunk. |
| pull request | fabric propose | Moves the change draft → proposed. |
| merge | fabric accept | Integrates the change tip into trunk. |
| commit SHA | op-id actor:seq | A stable (actor, sequence) coordinate, not a content hash. |
HEAD / a ref | frontier | The end of the log: the latest point, and the only place you write. |
Change
A change is Fabric’s unit of work: it replaces the branch. You fork an
isolated op-set from the current trunk frontier, edit, and integrate it forward
through propose → accept. Isolation is a guarantee, not ceremony: unreviewed
ops can never land on trunk, because propose → review → accept is the only
path in. A half-finished or unapproved change cannot corrupt what others build
on.
Trunk
The trunk is the converging head your changes integrate into: Fabric’s
main. Trunks are per-subtree: independent areas of the repo advance
independently rather than false-coupling through one global head.
Frontier
The frontier is the end of the log: the latest point, and the only place
you can write. It’s Fabric’s analog of a ref or HEAD: it identifies a version
of the repo, and replaying the log up to it produces the file state at that
point. New work always attaches here.
Forward-only: what does not exist
- No
rebase, no--force, no history rewrite. The log only ever grows. - No detached work you can lose. Your work lives on the change until accepted.
- No merge-marker editing on push. Trunk only changes when a change is accepted.
You cannot go back to an earlier point in the log and fork new work from it. The only direction is forward, at the frontier. Viewing the past is still easy, but strictly read-only: see Time-travel.