Skip to content
Merged
Show file tree
Hide file tree
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
6 changes: 6 additions & 0 deletions docs/snippets/tables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export const PyVersioningRollback = "table.restore(version_after_mod)\nversions

export const PyVersioningTags = "# Create a tag pointing at a specific version\ntable.tags.create(\"baseline\", 1)\ntable.tags.create(\"with-edits\", table.version)\n\n# List all tags on this table\nprint(table.tags.list())\n\n# Look up the version a tag points at\nprint(table.tags.get_version(\"baseline\"))\n\n# Move an existing tag to a different version\ntable.tags.update(\"baseline\", 2)\n\n# Check out a version by tag name\ntable.checkout(\"baseline\")\nprint(table.version)\n\n# Delete a tag (does not delete the underlying version)\ntable.tags.delete(\"with-edits\")\n\n# Return to the latest version\ntable.checkout_latest()\n";

export const PyVersioningBranches = "# Fork a new branch from the latest version of main\nexperiment = table.branches.create(\"experiment\")\nprint(experiment.current_branch()) # \"experiment\"\n\n# Writes on the branch handle do not affect main\nexperiment.add([{\"author\": \"Maya\", \"quote\": \"draft idea\"}])\n\n# List all branches on the table\nprint(table.branches.list())\n\n# Reopen an existing branch later (writable handle that tracks the branch tip)\nexperiment = table.branches.checkout(\"experiment\")\n\n# Pin a branch to a specific version (read-only view of that version)\nsnapshot = table.branches.checkout(\"experiment\", version=2)\n\n# Open a branch directly from the connection\nexperiment = db.open_table(\"my_table\", branch=\"experiment\")\n\n# Delete a branch when you're done with it\ntable.branches.delete(\"experiment\")\n";

export const PyVersioningUpdateData = "table.update(where=\"author='Richard'\", values={\"author\": \"Richard Daniel Sanchez\"})\nrows_after_update = table.count_rows(\"author = 'Richard Daniel Sanchez'\")\nprint(f\"Rows updated to Richard Daniel Sanchez: {rows_after_update}\")\n";

export const TsAddColumnsCalculated = "// Add a discounted price column (10% discount)\nawait schemaAddTable.addColumns([\n {\n name: \"discounted_price\",\n valueSql: \"cast((price * 0.9) as float)\",\n },\n]);\n";
Expand Down Expand Up @@ -218,6 +220,8 @@ export const TsVersioningRollback = "await table.checkout(versionAfterMod);\nawa

export const TsVersioningTags = "const tags = await tagsTable.tags();\n\n// Create a tag pointing at a specific version\nawait tags.create(\"baseline\", 1);\nawait tags.create(\"with-edits\", await tagsTable.version());\n\n// List all tags on this table\nconsole.log(await tags.list());\n\n// Look up the version a tag points at\nconsole.log(await tags.getVersion(\"baseline\"));\n\n// Move an existing tag to a different version\nawait tags.update(\"baseline\", 2);\n\n// Check out a version by tag name\nawait tagsTable.checkout(\"baseline\");\nconsole.log(await tagsTable.version());\n\n// Delete a tag (does not delete the underlying version)\nawait tags.delete(\"with-edits\");\n\n// Return to the latest version\nawait tagsTable.checkoutLatest();\n";

export const TsVersioningBranches = "const branches = await table.branches();\n\n// Fork a new branch from the latest version of main\nconst experiment = await branches.create(\"experiment\");\nconsole.log(experiment.currentBranch); // \"experiment\"\n\n// Writes on the branch handle do not affect main\nawait experiment.add([{ author: \"Maya\", quote: \"draft idea\" }]);\n\n// List all branches on the table\nconsole.log(await branches.list());\n\n// Reopen an existing branch later (writable handle that tracks the branch tip)\nconst tracking = await branches.checkout(\"experiment\");\n\n// Pin a branch to a specific version (read-only view of that version)\nconst snapshot = await branches.checkout(\"experiment\", 2);\n\n// Delete a branch when you're done with it\nawait branches.delete(\"experiment\");\n";

export const TsVersioningUpdateData = "await table.update({\n where: \"author = 'Richard'\",\n values: { author: \"Richard Daniel Sanchez\" },\n});\nconst rowsAfterUpdate = await table.countRows(\n \"author = 'Richard Daniel Sanchez'\",\n);\nconsole.log(`Rows updated to Richard Daniel Sanchez: ${rowsAfterUpdate}`);\n";

export const RsAddColumnsCalculated = "// Add a discounted price column (10% discount)\nschema_add_table\n .add_columns(\n NewColumnTransform::SqlExpressions(vec![(\n \"discounted_price\".to_string(),\n \"cast((price * 0.9) as float)\".to_string(),\n )]),\n None,\n )\n .await\n .unwrap();\n";
Expand Down Expand Up @@ -318,5 +322,7 @@ export const RsVersioningRollback = "table.checkout(version_after_mod).await.unw

export const RsVersioningTags = "let mut tags = tags_table.tags().await.unwrap();\n\n// Create a tag pointing at a specific version\ntags.create(\"baseline\", 1).await.unwrap();\nlet current_version = tags_table.version().await.unwrap();\ntags.create(\"with-edits\", current_version).await.unwrap();\n\n// List all tags on this table\nlet all_tags = tags.list().await.unwrap();\nprintln!(\"Tags: {:?}\", all_tags);\n\n// Look up the version a tag points at\nlet baseline_version = tags.get_version(\"baseline\").await.unwrap();\nprintln!(\"baseline -> v{}\", baseline_version);\n\n// Move an existing tag to a different version\ntags.update(\"baseline\", 2).await.unwrap();\n\n// Check out a version by tag name (separate method in Rust)\ntags_table.checkout_tag(\"baseline\").await.unwrap();\nprintln!(\"Current version: {}\", tags_table.version().await.unwrap());\n\n// Delete a tag (does not delete the underlying version)\ntags.delete(\"with-edits\").await.unwrap();\n\n// Return to the latest version\ntags_table.checkout_latest().await.unwrap();\n";

export const RsVersioningBranches = "// Fork a new branch from the latest version of main\nlet experiment = table.create_branch(\"experiment\", None, None).await.unwrap();\nprintln!(\"{:?}\", experiment.current_branch()); // Some(\"experiment\")\n\n// List all branches on the table\nlet all_branches = table.list_branches().await.unwrap();\nprintln!(\"Branches: {:?}\", all_branches);\n\n// Reopen an existing branch later (writable handle that tracks the branch tip)\nlet tracking = table.checkout_branch(\"experiment\", None).await.unwrap();\n\n// Pin a branch to a specific version (read-only view of that version)\nlet snapshot = table.checkout_branch(\"experiment\", Some(2)).await.unwrap();\n\n// Delete a branch when you're done with it\ntable.delete_branch(\"experiment\").await.unwrap();\n";

export const RsVersioningUpdateData = "table\n .update()\n .only_if(\"author = 'Richard'\")\n .column(\"author\", \"'Richard Daniel Sanchez'\")\n .execute()\n .await\n .unwrap();\nlet rows_after_update = table\n .count_rows(Some(\"author = 'Richard Daniel Sanchez'\".to_string()))\n .await\n .unwrap();\nprintln!(\n \"Rows updated to Richard Daniel Sanchez: {}\",\n rows_after_update\n);\n";

53 changes: 53 additions & 0 deletions docs/tables/versioning.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ import {
PyVersioningTags as VersioningTags,
TsVersioningTags as TsVersioningTags,
RsVersioningTags as RsVersioningTags,
PyVersioningBranches as VersioningBranches,
TsVersioningBranches as TsVersioningBranches,
RsVersioningBranches as RsVersioningBranches,
RsVersioningMakeQuotesReader as RsVersioningMakeQuotesReader,
} from '/snippets/tables.mdx';

Expand Down Expand Up @@ -218,6 +221,56 @@ Deleting a tag only removes the label, not the version it points to. After
deletion, the underlying table version becomes eligible for cleanup again.
</Note>

## Branches

Branches are isolated, writable lines of history forked from another branch
(or a specific version of one). Use them when you need to experiment with
schema or data changes, run an A/B compaction strategy, or stage a backfill
without affecting readers on `main`. Conceptually they sit next to tags:
**tags label a single version**, while **branches let history diverge** from
that point.

The branch manager supports the standard operations — `create`, `list`,
`checkout`, `delete` — and `checkout` / `create` return a new table handle
scoped to the branch. Writes on that handle do not touch `main`. The
original handle keeps pointing at the branch it was opened on, which is
reported by `current_branch()` (`null` / `None` for `main`).

<CodeGroup>
<CodeBlock filename="Python" language="Python" icon="python">
{VersioningBranches}
</CodeBlock>

<CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
{TsVersioningBranches}
</CodeBlock>

<CodeBlock filename="Rust" language="Rust" icon="rust">
{RsVersioningBranches}
</CodeBlock>
</CodeGroup>

In Python, you can also open a branch directly from the connection by
passing `branch=` to `open_table()`. Combine it with `version=` to open a
read-only handle pinned to a specific version on that branch:

```python
# Latest version of the experiment branch (writable)
experiment = db.open_table("my_table", branch="experiment")

# Pinned to v3 of the experiment branch (read-only)
snapshot = db.open_table("my_table", branch="experiment", version=3)
```

<Note>
Each branch handle has its own freshness state and version pin, so reopening
a branch on a new connection — or restoring one from a pickled handle —
keeps you on the branch instead of silently reverting to `main`.

Branches are supported by tables backed by the Lance format directly and by
remote tables served by LanceDB Enterprise.
</Note>

## Delete Data From the Table

Let's demonstrate how deletions also create new versions:
Expand Down
Loading