# Dolt Branch Management for Datasets: CLI and SQL Workflows Explained

> Master Dolt branch management for datasets. Learn Git-like workflows using CLI and SQL commands for efficient data versioning and collaboration.

- Repository: [DoltHub/dolt](https://github.com/dolthub/dolt)
- Tags: how-to-guide
- Published: 2026-03-14

---

**Dolt implements Git-like branch management for datasets through a unified storage layer where branches are named references pointing to commits, accessible via CLI commands, SQL stored procedures, and the Go API.**

Dolt branch management for datasets enables version-controlled database workflows where every branch represents an independent line of development. In the dolthub/dolt repository, branches function as mutable pointers to commits—stored as `refs/heads/<branch-name>`—while the SQL engine exposes them through the `dolt_branches` system table and stored procedures. This architecture ensures that whether you invoke `dolt branch` from the command line or execute `CALL dolt_branch()` from a SQL client, both operations manipulate the same underlying ref store and dataset abstractions.

## How Dolt Branches Work Internally

Dolt treats a **branch** exactly like Git: it is a named reference that points to a commit (the *head* of the branch). However, Dolt extends this concept to SQL databases through a **dataset** abstraction that bridges Git semantics with relational data.

### The Ref-Dataset Relationship

At the storage layer, every branch is a `ref.DoltRef` object with the form `refs/heads/<branch-name>` that stores a commit hash. The head of a branch is represented as a **dataset** whose name matches the branch name. According to the implementation in [`go/store/datas/dataset.go`](https://github.com/dolthub/dolt/blob/main/go/store/datas/dataset.go), the `Dataset` type represents the mutable root of a branch and provides methods like `MaybeHead` and `Commit` to read or update the head commit.

The resolution from branch name to dataset occurs through [`go/store/spec/spec.go`](https://github.com/dolthub/dolt/blob/main/go/store/spec/spec.go), where `Spec.ForDataset("mybranch")` parses the identifier and returns a live `Dataset` object. This abstraction is used uniformly by the SQL engine, CLI, and Go API to ensure consistent access patterns.

### The Dolt Branches System Table

The SQL engine exposes branch metadata through `dolt_branches`, a virtual table defined in [`go/libraries/doltcore/sqle/tables.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/sqle/tables.go). Unlike physical tables, `dolt_branches` is built on-the-fly by the `BranchRowIter` iterator, which scans all `refs/heads/*` entries in the ref store. This guarantees that any branch created via the CLI immediately appears in SQL queries without synchronization delays.

## Branch Operations Across Interfaces

Dolt provides three equivalent interfaces for branch management: the CLI (`dolt branch`), SQL stored procedures (`CALL dolt_branch(...)`), and the Go API ([`go/libraries/doltcore/env/actions/branch.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/env/actions/branch.go)). All three layers invoke the same core functions, ensuring behavioral consistency.

### Creating Branches

To create a branch from the current HEAD or a specific start point:

**CLI:**

```bash
dolt branch feature1
dolt branch -b feature1 main

```

**SQL:**

```sql
CALL dolt_branch('feature1');
CALL dolt_branch('feature1', 'main');

```

**Go API:**

```go
import "github.com/dolthub/dolt/go/libraries/doltcore/env/actions"

// Create from current HEAD
err := actions.CreateBranchOnDB(ctx, db, "feature1", "", false, headRef, rsc)

// Create from specific branch
err := actions.CreateBranchOnDB(ctx, db, "feature1", "main", false, headRef, rsc)

```

Behind the scenes, `CreateBranchOnDB` in [`go/libraries/doltcore/env/actions/branch.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/env/actions/branch.go) validates the branch name using `ValidateDatasetId`, creates a new `ref.DoltRef` pointing to the start commit, and writes it to the ref store atomically.

### Renaming Branches

Rename operations move the reference while preserving the commit history:

**CLI:**

```bash
dolt branch -m old_name new_name

```

**SQL:**

```sql
CALL dolt_branch('-m', 'old_name', 'new_name');

```

**Go API:**

```go
err := actions.RenameBranch(ctx, dbData, "old_name", "new_name", nil, false, rsc)

```

The `RenameBranch` function ensures the target name does not already exist, then renames the ref from `refs/heads/old_name` to `refs/heads/new_name` in the ref store.

### Copying Branches

Branch copying creates a new reference pointing to the same commit as the source:

**CLI:**

```bash
dolt branch --copy dev dev_backup

```

**SQL:**

```sql
CALL dolt_branch('--copy', 'dev', 'dev_backup');

```

**Go API:**

```go
err := actions.CopyBranch(ctx, env, "dev", "dev_backup", false)

```

As implemented in [`actions/branch.go`](https://github.com/dolthub/dolt/blob/main/actions/branch.go), `CopyBranch` loads the source branch's head commit and creates a new ref `refs/heads/dev_backup` that points to the same hash, performing the operation atomically.

### Deleting Branches with Safety Checks

Dolt prevents accidental data loss by validating that a branch is fully merged before deletion, unless the force flag is used:

**CLI:**

```bash

# Safe delete (requires merged status)

dolt branch -d feature1

# Force delete

dolt branch -D feature1

```

**SQL:**

```sql
-- Safe delete
CALL dolt_branch('-d', 'feature1');

-- Force delete
CALL dolt_branch('-D', 'feature1');

```

**Go API:**

```go
opts := actions.BranchDeleteOptions{Force: false}
err := actions.DeleteBranch(ctx, dbData, "feature1", opts, nil, rsc)

```

The `DeleteBranch` function in [`go/libraries/doltcore/env/actions/branch.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/env/actions/branch.go) first calls `validateBranchMergedIntoCurrentWorkingBranch` to verify that the branch has been merged into the current working branch. If the check fails and `Force` is false, the operation returns an error. Passing the force flag (`-D` or `Force: true`) bypasses this validation.

### Listing Branches via System Tables

Query branch metadata using the virtual table:

```sql
SELECT name, head_commit_hash, head_commit_date
FROM dolt_branches
ORDER BY name;

```

This query executes against `doltBranchesTable` in [`go/libraries/doltcore/sqle/tables.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/sqle/tables.go), where `BranchRowIter` iterates over all `refs/heads/*` references and extracts commit metadata without requiring physical table storage.

## Key Source Files

Understanding the implementation details requires examining these specific files in the dolthub/dolt repository:

- **[`go/libraries/doltcore/env/actions/branch.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/env/actions/branch.go)** – Core logic for `CreateBranchOnDB`, `RenameBranch`, `CopyBranch`, and `DeleteBranch`. Validates branch names, manages ref updates, and handles remote tracking.

- **[`go/cmd/dolt/commands/branch.go`](https://github.com/dolthub/dolt/blob/main/go/cmd/dolt/commands/branch.go)** – CLI command implementation that parses arguments (`-m`, `-d`, `-c`) and translates them into SQL stored procedure calls or direct Go API invocations.

- **[`go/libraries/doltcore/sqle/tables.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/sqle/tables.go)** – Defines `doltBranchesTable` and `BranchRowIter`, which generate rows for the `dolt_branches` system table by reading the ref store.

- **[`go/store/spec/spec.go`](https://github.com/dolthub/dolt/blob/main/go/store/spec/spec.go)** – Contains `ForDataset` and `Spec.GetDataset`, which resolve branch names to `Dataset` objects.

- **[`go/store/datas/dataset.go`](https://github.com/dolthub/dolt/blob/main/go/store/datas/dataset.go)** – Implements the `Dataset` abstraction representing a branch head, providing access to the root hash and commit history.

- **[`go/libraries/doltcore/sqle/enginetest/dolt_queries_procedures.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/sqle/enginetest/dolt_queries_procedures.go)** – Comprehensive test suite ensuring the `dolt_branch` stored procedure behaves identically to the CLI.

## Summary

- **Unified storage layer** – Dolt branch management for datasets uses a single ref store (`refs/heads/<name>`) accessed by the CLI, SQL engine, and Go API, ensuring immediate consistency across interfaces.

- **Dataset abstraction** – Branches are first-class datasets identified by name, resolved through `Spec.ForDataset()` and manipulated via the `Dataset` type in [`go/store/datas/dataset.go`](https://github.com/dolthub/dolt/blob/main/go/store/datas/dataset.go).

- **Virtual metadata** – The `dolt_branches` table is built on-the-fly from the ref store by `BranchRowIter`, eliminating synchronization lag between branch creation and visibility in SQL.

- **Safety mechanisms** – Delete operations invoke `validateBranchMergedIntoCurrentWorkingBranch` to prevent data loss, with force flags available for intentional deletion of unmerged branches.

- **Atomic operations** – All branch mutations (create, rename, copy, delete) update the ref store atomically, maintaining ACID properties for database versioning workflows.

## Frequently Asked Questions

### How does Dolt branch management differ from Git branch management?

Dolt branch management mirrors Git's semantics—branches are named references to commits—but extends them to SQL databases through the dataset abstraction. While Git operates on file trees, Dolt's branches in [`go/store/datas/dataset.go`](https://github.com/dolthub/dolt/blob/main/go/store/datas/dataset.go) point to root hashes of database tables, enabling `CALL dolt_branch()` operations within SQL transactions and exposing branch metadata via the `dolt_branches` system table.

### Can I create a branch from a specific commit or only from branch names?

You can create branches from both specific commits and existing branch names. The `dolt_branch` stored procedure and CLI accept an optional start-point parameter. According to [`go/libraries/doltcore/env/actions/branch.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/env/actions/branch.go), `CreateBranchOnDB` accepts a `startPt` string that can resolve to any commit hash or branch name, creating the new `refs/heads/<branch>` reference pointing to that specific commit.

### Why does the `dolt_branches` table show branches immediately after CLI creation?

The `dolt_branches` table is a virtual table implemented in [`go/libraries/doltcore/sqle/tables.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/sqle/tables.go) rather than a physical table. The `BranchRowIter` scans the ref store dynamically for all `refs/heads/*` entries whenever a query executes. Because both the CLI and SQL engine write to the same ref store in [`go/store/spec/spec.go`](https://github.com/dolthub/dolt/blob/main/go/store/spec/spec.go), changes are visible immediately without cache invalidation or replication delays.

### What happens when I force-delete a branch that isn't merged?

When force-deleting via `dolt branch -D` or `CALL dolt_branch('-D', 'name')`, Dolt skips the merge validation performed by `validateBranchMergedIntoCurrentWorkingBranch` in [`go/libraries/doltcore/env/actions/branch.go`](https://github.com/dolthub/dolt/blob/main/go/libraries/doltcore/env/actions/branch.go). The `DeleteBranch` function removes the `refs/heads/<name>` reference from the store, making the branch unreachable from standard queries (though the commit data persists until garbage collection). This operation is irreversible via standard branch commands, requiring reflog or backup recovery if needed.