Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 106 additions & 3 deletions docs/tables/branching.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,19 @@ below.
## Apply branch-tested changes to `main`

<Warning>
A branch has its own writable history. LanceDB does not currently reconcile one
branch's history with another or detect conflicts between them. To carry
accepted work forward, rerun the validated operation against `main` or
A branch has its own writable history. Outside of the [diff and merge
APIs](#compare-and-merge-a-branch-into-main) — which are available on
LanceDB Enterprise and promote added columns only — LanceDB does not reconcile
one branch's history with another or detect conflicts between them. To carry
other accepted work forward, rerun the validated operation against `main` or
explicitly write selected results to it.
</Warning>

How you apply a validated change depends on the type of work:

- **Added columns (Enterprise):** review the branch with `diff`, then promote
the new columns onto `main` with `merge`. See
[Compare and merge a branch into `main`](#compare-and-merge-a-branch-into-main).
- **Backfill or transformation:** rerun the validated job against `main`.
- **Schema change:** apply the same reviewed schema operation to `main`.
- **Index change:** build the index on `main` using the configuration validated
Expand Down Expand Up @@ -249,6 +254,104 @@ newer values with the same key. Read and upsert the whole branch only when that
overwrite is intentional; otherwise, filter the branch read to the rows you
intend to apply.

## Compare and merge a branch into `main`

<Badge color="red">Enterprise</Badge>

On LanceDB Enterprise, branches expose two review-and-land calls that let you
inspect what a branch has changed relative to `main` and then promote its new
columns onto `main` in place — without reissuing the branch's writes.

<Info>
`diff` and `merge` are available on Enterprise (remote) tables only. On local
tables both calls raise `NotSupported`. `merge` currently promotes added
columns; use the [upsert](#upsert-selected-branch-rows-into-main) or rerun
patterns above for row and index changes.
</Info>

### Diff a branch

`diff` reads the branch and `main`, and returns a summary of what has changed:
which columns were added, removed, or altered; which indexes were added or
removed; row-count deltas; and — most importantly — a list of merge blockers
explaining why the branch cannot currently be merged, if any.

<CodeGroup>
```python Python icon="python"
diff = table.branches.diff("exp")

print(diff["addedColumns"]) # columns the branch introduced
print(diff["mergeable"]) # True when there are no blockers
print(diff["mergeBlockers"]) # list of {"code", "message"} entries
```

```typescript TypeScript icon="square-js"
const diff = await table.branches.diff("exp");

console.log(diff.addedColumns); // columns the branch introduced
console.log(diff.mergeable); // true when there are no blockers
console.log(diff.mergeBlockers); // array of { code, message } entries
```
</CodeGroup>

Common merge blocker codes include `BaseMoved` (the branch's parent no longer
matches `main`'s latest), `RowsChanged`, `ColumnRemoved`, `ColumnChanged`,
`NoMergeableChanges`, `NoColumnChanges`, `InputColumnDependency`, and
`ParentNotMain`. Newer server codes surface as `Unknown` so older clients
keep working.

### Merge a branch

`merge` promotes a branch's added columns onto `main`. It is a review-and-land
operation: the server re-evaluates the diff at request time, and either lands
the promotion or rejects it with the same blockers `diff` would report. A
rejected merge is not an exception — it resolves with `status="rejected"` so
you can inspect the blockers and decide what to do next.

Set `dry_run=True` (Python) or `dryRun: true` (TypeScript) to preview the
merge without landing it. The result includes a `preview.promoted_columns`
list showing which columns the merge would (or did) promote.

<CodeGroup>
```python Python icon="python"
# Preview first — this does not modify main.
preview = table.branches.merge("exp", dry_run=True)
print(preview["status"]) # "ready" | "rejected" | ...
print(preview["preview"]["promotedColumns"])

# Land the merge.
result = table.branches.merge("exp")
if result["status"] == "merged":
print("landed at main version", result["mainVersionAfter"])
elif result["status"] == "rejected":
for blocker in result["diff"]["mergeBlockers"]:
print(blocker["code"], blocker["message"])
```

```typescript TypeScript icon="square-js"
// Preview first — this does not modify main.
const preview = await table.branches.merge("exp", true);
console.log(preview.status); // "ready" | "rejected" | ...
console.log(preview.preview.promotedColumns);

// Land the merge.
const result = await table.branches.merge("exp");
if (result.status === "merged") {
console.log("landed at main version", result.mainVersionAfter);
} else if (result.status === "rejected") {
for (const blocker of result.diff.mergeBlockers) {
console.log(blocker.code, blocker.message);
}
}
```
</CodeGroup>

Possible `status` values are `ready` (returned by `dry_run` when the merge
would land), `merged` (a real merge that landed), `rejected` (server declined;
see `diff.mergeBlockers`), `notImplemented`, and `unknown` for forward
compatibility. Merge requests are not retried on rejection — the response
carries everything you need to decide next steps.

## Build indexes on a branch

One of the most useful things a branch buys you is a safe place to build and
Expand Down
Loading