fluree branch
Manage branches for a ledger.
Subcommands
fluree branch create
Create a new branch.
Usage:
fluree branch create <NAME> [OPTIONS]
Arguments:
| Argument | Description |
|---|---|
<NAME> | Name for the new branch (e.g., “dev”, “feature-x”). Cannot contain /, :, @ or #; see naming rules |
Options:
| Option | Description |
|---|---|
-l, --ledger <LEDGER> | Ledger name (defaults to active ledger) |
--from <BRANCH> | Source branch to create from (defaults to “main”) |
--at <TIME> | Point on the source branch to branch at (defaults to its HEAD). Same spellings as query --at: t:<N> or a bare transaction number, time:<ISO-8601> (commit event time; iso: is an alias) or a bare ISO-8601 timestamp, recorded:<ISO-8601> (the wall-clock time the commit was recorded), commit:<prefix> or a bare hex digest prefix (min 6 chars), a full CID, or latest / t:latest (the HEAD). A bare integer is read as a transaction number, so use commit:<prefix> to force an all-digit prefix. |
--remote <REMOTE> | Execute against a remote server |
Description:
Creates a new branch for a ledger. By default the branch starts at the source branch’s current HEAD, and is fully isolated — subsequent transactions on either branch are invisible to the other.
Pass --at to branch from an earlier point on the source branch instead of its HEAD. The new branch starts at the commit that fluree query --at with the same value reads on the source: --at time:2026-01-01T00:00:00Z gives you the data as of that instant, resolved exactly as a query at that time resolves it. A time before the source’s first commit, a malformed timestamp, a transaction number below 1, and snapshot:<id> (which names a graph source’s table snapshot, not a commit) are rejected.
The commit must be on the source branch’s line of commits, which runs through its fork point into the branch it came from. A commit that reached the branch through a merge is refused: the branch never replays it, because what the merge contributed is folded into the merge commit. Branch at the merge commit instead, or on the branch that made the commit. The new branch starts with no index and replays from genesis on first query.
Branches can be nested: you can create a branch from any existing branch, not just “main”.
Examples:
# Create a branch from main (default)
fluree branch create dev
# Create a branch for a specific ledger
fluree branch create dev --ledger mydb
# Create a branch from another branch
fluree branch create feature-x --from dev
# Branch at a historical point on main (transaction number)
fluree branch create rewind --at t:5
fluree branch create rewind --at 5 # same commit
# Branch at a historical commit by hex-digest prefix
fluree branch create rewind --at 3dd028a7
# Branch at the data as of a point in time
fluree branch create q2 --at time:2026-07-01T00:00:00Z
# Create a branch on a remote server
fluree branch create staging --ledger mydb --remote origin
Output:
Created branch 'dev' from 'main' at t=5
Ledger ID: mydb:dev
fluree branch list
List all branches for a ledger.
Usage:
fluree branch list [LEDGER] [OPTIONS]
Arguments:
| Argument | Description |
|---|---|
[LEDGER] | Ledger name (defaults to active ledger) |
Options:
| Option | Description |
|---|---|
--remote <REMOTE> | List branches on a remote server |
Examples:
# List branches for the active ledger
fluree branch list
# List branches for a specific ledger
fluree branch list mydb
# List branches on a remote server
fluree branch list mydb --remote origin
Output:
BRANCH T SOURCE
main 5 -
dev 7 main
feature-x 8 dev
fluree branch drop
Drop a branch from a ledger.
Usage:
fluree branch drop <NAME> [OPTIONS]
Arguments:
| Argument | Description |
|---|---|
<NAME> | Branch name to drop (e.g., “dev”, “feature-x”) |
Options:
| Option | Description |
|---|---|
-l, --ledger <LEDGER> | Ledger name (defaults to active ledger) |
--remote <REMOTE> | Execute against a remote server |
Description:
Drops a branch from a ledger. The main branch cannot be dropped.
- Leaf branches (no children) are fully deleted — storage artifacts are removed and the NsRecord is purged.
- Branches with children are retracted (hidden from listings, reject new transactions) but storage is preserved so that child branches continue to work. When the last child is eventually dropped, the retracted parent is automatically cascade-purged.
Examples:
# Drop a branch
fluree branch drop dev
# Drop a branch for a specific ledger
fluree branch drop dev --ledger mydb
# Drop a branch on a remote server
fluree branch drop staging --ledger mydb --remote origin
Output (leaf branch):
Dropped branch 'dev'.
Artifacts deleted: 5
Output (branch with children):
Branch 'dev' retracted (has children, storage preserved).
Output (cascade):
Dropped branch 'feature'.
Artifacts deleted: 3
Cascaded drops: mydb:dev
fluree branch rebase
Rebase a branch onto its source branch’s current HEAD.
Usage:
fluree branch rebase <NAME> [OPTIONS]
Arguments:
| Argument | Description |
|---|---|
<NAME> | Branch name to rebase (e.g., “dev”, “feature-x”) |
Options:
| Option | Description |
|---|---|
-l, --ledger <LEDGER> | Ledger name (defaults to active ledger) |
--strategy <STRATEGY> | Conflict resolution strategy (default: “take-both”). Options: take-both, abort, take-source, take-branch, skip |
--remote <REMOTE> | Execute against a remote server |
Description:
Replays a branch’s unique commits on top of the source branch’s current HEAD. This brings the branch up to date with upstream changes, and rewrites the branch’s commits to do it. To keep the branch’s commits as they are, merge the source into the branch instead. The main branch cannot be rebased.
A branch that already merged its source in is rebased on its own commits, and that merge is replayed among them. Only the edits that resolved the overlap between the two sides are replayed with it. Everything else it carries came from the source, which already holds it.
If the branch has no unique commits, a fast-forward rebase is performed — the branch point is simply updated to the source’s current HEAD.
Conflicts occur when both the branch and source have modified the same (subject, predicate, graph) tuples. See conflict strategies for details.
Each replayed commit is validated against the source branch’s SHACL configuration and shapes, exactly as a transaction would be. A commit that conformed on the branch can violate a shape the source installed since the fork; the first such replay aborts the whole rebase with the same violation report a rejected transaction prints, naming the commit it stopped on, and the branch is left as it was.
Examples:
# Rebase with default strategy
fluree branch rebase dev
# Rebase with abort-on-conflict strategy
fluree branch rebase dev --strategy abort
# Rebase for a specific ledger
fluree branch rebase feature-x --ledger mydb --strategy take-source
# Rebase on a remote server
fluree branch rebase dev --ledger mydb --remote origin
Output (fast-forward):
Fast-forward rebase of 'dev' to t=5.
Output (with replay):
Rebased 'dev': 3 commits replayed, 0 skipped, 1 conflicts, 0 failures.
New branch point: t=8
fluree branch diff
Show a read-only merge preview between two branches.
Usage:
fluree branch diff <SOURCE> [OPTIONS]
Arguments:
| Argument | Description |
|---|---|
<SOURCE> | Source branch name to preview merging from (e.g., “dev”, “feature-x”) |
Options:
| Option | Description |
|---|---|
--target <BRANCH> | Target branch to preview merging into (defaults to the branch the source was created from) |
--max-commits <N> | Cap on per-side commit summaries shown (default: 50; pass 0 for unbounded in local mode) |
--max-conflict-keys <N> | Cap on conflict keys shown (default: 50; pass 0 for unbounded in local mode) |
--no-conflicts | Skip conflict computation for a cheaper preview |
--conflict-details | Include source/target flake values for returned conflict keys |
--strategy <STRATEGY> | Strategy used for conflict detail labels and for resolving the change set that validation stages (default: take-both). Options: take-both, abort, take-source, take-branch |
--no-validate | Skip SHACL validation of the merged state. Validation runs by default and its outcome folds into mergeable |
--json | Emit the raw JSON preview |
-l, --ledger <LEDGER> | Ledger name (defaults to active ledger) |
--remote <REMOTE> | Execute against a remote server |
Description:
branch diff reports ahead/behind commits, fast-forward eligibility, and conflicting (subject, predicate, graph) keys without mutating state. It previews the same directions branch merge supports, so fluree branch diff main --target dev works. With --conflict-details, the preview also shows the source and target values for the returned conflict keys and annotates what the selected strategy would do.
By default the preview also stages the merge’s resolved change set on the target and validates it against the target’s SHACL configuration and shapes, through the same code path branch merge uses. The validation: line reports conforms or the violation report the merge would fail with, and mergeable: is yes only when the strategy applies and the result conforms. A preview that says mergeable: yes therefore means neither the strategy nor the target’s shapes will reject the merge. Other conditions still apply at commit time, novelty backpressure among them, so a ledger due for indexing can refuse a merge the preview passed. Fast-forward previews carry no validation line: the adopted commits were validated when they were authored. Pass --no-validate for a cheaper count-only preview.
Examples:
# Preview merging dev into its parent
fluree branch diff dev
# Preview a specific target
fluree branch diff dev --target main
# Show value details and source-winning labels
fluree branch diff dev --target main --conflict-details --strategy take-source
# Emit raw JSON for UI tooling
fluree branch diff dev --conflict-details --json
fluree branch merge
Merge a source branch into a target branch.
Usage:
fluree branch merge <SOURCE> [OPTIONS]
Arguments:
| Argument | Description |
|---|---|
<SOURCE> | Source branch name to merge from (e.g., “dev”, “feature-x”) |
Options:
| Option | Description |
|---|---|
-l, --ledger <LEDGER> | Ledger name (defaults to active ledger) |
--target <BRANCH> | Target branch to merge into (defaults to the branch the source was created from) |
--strategy <STRATEGY> | Conflict resolution strategy (default: take-both). Options: take-both, abort, take-source, take-branch. |
--remote <REMOTE> | Execute against a remote server |
Description:
Merges a source branch into a target branch. Any two branches of a ledger can be merged: a branch into the one it came from, a branch into one created from it, or two branches that share an earlier commit. main can be the source when --target names where to merge it.
When --target is omitted, the target is the branch the source was created from. Only then does the source need to have been created from another branch.
The merge fast-forwards when the target’s head is on the source’s line of commits, which means the source continues where the target left off. The target then adopts the source’s head. Otherwise the merge folds the source’s changes into one commit on the target, and --strategy controls how conflicting edits are resolved (mirroring branch rebase).
Each branch numbers its commits from its own fork point, so the two branches’ t values cannot be compared. The merge finds what each side changed by commit identity instead. A branch that already merged the other in does not count that merge as its own change, because those changes came from the other side to begin with. The edits that resolved the overlap are its own, so merging back does not undo a resolution.
After a successful merge, the source branch remains intact and can continue to receive new transactions and be merged again. Only the new commits since the last merge (or branch creation) are copied.
A non-fast-forward merge is validated against the target’s SHACL configuration and shapes before anything is written, exactly as a transaction producing the merged state would be. This matters most for take-both, whose “both values coexist” resolution can breach a sh:maxCount on a property both sides changed: the merge is rejected with the same violation report a rejected transaction prints, and the target is left untouched. Warn-mode graphs log and proceed. Shapes referenced through a cross-ledger f:shapesSource are resolved and enforced like any other. Use branch diff to see the outcome before merging.
Examples:
# Merge dev into main (inferred from branch point)
fluree branch merge dev
# Merge feature-x into dev (explicit target)
fluree branch merge feature-x --target dev
# Bring main's latest into a branch, keeping the branch's history
fluree branch merge main --target dev
# Merge for a specific ledger
fluree branch merge dev --ledger mydb
# Merge with source-winning conflict resolution
fluree branch merge dev --target main --strategy take-source
# Merge on a remote server
fluree branch merge dev --ledger mydb --remote origin
Output:
Merged 'dev' into 'main' (fast-forward to t=8, 3 commits copied).
Output (non-fast-forward):
Merged 'dev' into 'main' (t=9, 3 commits copied, 1 conflicts).
fluree branch revert
Revert one or more commits by writing a new commit that undoes them — history is never rewritten, so earlier states stay reachable with --at.
fluree branch revert <COMMITS>...
fluree branch revert --from <COMMIT> --to <COMMIT>
Accepts either positional commit references (cherry-pick style, one or several) or a git-style range. Each commit reference may be a t:<N> or bare transaction number, a commit:<prefix> or bare hex digest prefix, or a full commit ID — the commit spellings branch create --at also accepts. A revert names the commit to undo, so it has no timestamp forms.
A commit must be on the branch’s own history, which is the line of commits reached by following each merge’s first parent. When the selected commits have nothing to undo, such as one that only registered a graph, no commit is written: the command reports that nothing was reverted and HEAD stays where it was. The genesis commit, a merge commit, and a commit that reached this branch through a merge are all refused: the first two have no single change to undo, and the third belongs to the branch that authored it, where its own history can say what changed after it. Revert it there and merge again.
The revert commit is validated against the branch’s SHACL configuration and shapes before it is written. Undoing a commit can remove a value a later shape requires (a sh:minCount, say); such a revert is rejected with the same violation report a rejected transaction prints, and the branch is left as it was. With --preview, the same staging and validation run without writing anything: revertable: yes means neither the strategy nor the branch’s shapes will reject the revert, and otherwise the validation: line carries the report it would fail with.
| Option | Description |
|---|---|
<COMMITS>... | Commits to revert (mutually exclusive with --from/--to) |
--from <COMMIT> | Range start (exclusive); requires --to |
--to <COMMIT> | Range end (inclusive); requires --from |
--branch <BRANCH> | Branch the revert commit is written to (defaults to the active branch) |
--strategy <STRATEGY> | Conflict resolution: abort (default), take-source, take-branch |
--preview | Show what the revert would do — resolved commit list, conflict count, the SHACL outcome, and whether it would proceed — without writing a commit |
--no-validate | With --preview: skip SHACL validation of the inverted state. Validation runs by default and folds into revertable |
--json | With --preview: emit the raw JSON RevertPreview instead of a summary |
-l, --ledger <LEDGER> | Ledger name (defaults to active ledger) |
--remote <REMOTE> | Execute against a remote server (by remote name) |
# Undo a single commit by transaction number
fluree branch revert t:42
# Cherry-pick two commits out
fluree branch revert t:42 t:47
# Revert a range, previewing conflicts first
fluree branch revert --from t:40 --to t:45 --preview