---
title: Branch Permissions
---


## What are Branch Permissions?

Branch permissions are a way of managing how users may interact with branches when running Doltgres
as a server (via the `doltgres` command). The branch permissions model is composed of two system
tables: `dolt_branch_control` and `dolt_branch_namespace_control`. The former table handles branch
modification, while the latter table handles branch creation.

## System Tables

Both system tables—`dolt_branch_control` and `dolt_branch_namespace_control`—have a similar schema.
Each column is composed of a string that represents a pattern-matching expression.

### `dolt_branch_control`

| Column      | Type | Case Sensitive |
| :---------- | :--- | :------------- |
| database    | TEXT | No             |
| branch      | TEXT | No             |
| user        | TEXT | Yes            |
| host        | TEXT | No             |
| permissions | TEXT | No             |

The `permissions` column accepts a comma-separated combination of the values `admin`, `write`, and
`read`.

### `dolt_branch_namespace_control`

| Column   | Type | Case Sensitive |
| :------- | :--- | :------------- |
| database | TEXT | No             |
| branch   | TEXT | No             |
| user     | TEXT | Yes            |
| host     | TEXT | No             |

### Available Permissions

| Permission | Effect                                                                                                                                                                                                                              |
| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| admin      | Grants all permissions available. In addition, grants write access to entries on both system tables, as long as the database and branch are equivalent, or they're subset of the database + branch that this permission belongs to. |
| write      | Grants the ability to write on the branch, as well as modify the branch in all possible ways (rename, delete, etc.).                                                                                                                |
| read       | Does not explicitly grant any permissions, as having the ability to read a branch is an irrevocable right for all users. This is just for the visual convenience, versus having an empty field.                                     |

Just to reiterate: remember that all users, even those without an entry at all, still have read access to all branches.
Permissions only affect modifying branches, and writing to the system tables.

### Pattern Matching

The form of pattern matching that each column implements is very similar to how `LIKE` expressions are parsed.
Most characters are interpreted as-is, with the exception of three characters.

| Character | Function                                                                                                                                                                                    |
| :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| \_        | Matches a single character, regardless of what that character is.                                                                                                                           |
| %         | Matches zero or more characters, regardless of what those characters are.                                                                                                                   |
| \         | Escapes the next character, allowing it to be compared literally. This is only useful when attempting to match one of these special characters, as it is otherwise ignored (has no effect). |

Due to the above rules, it is possible to write two different expressions that have the exact same match characteristics.
Rather than allow duplicates, Doltgres processes each expression to find its most concise equivalent (folding the expression).
There are two rules that are repeatedly applied to strings until neither applies.
The first rule replaces `%%` with `%`.
The second rule replaces `%_` with `_%`.

The first rule is very straightforward, as two consecutive "zero or more" characters will still match "zero or more" characters.
The second rule simplifies parsing, and gives a definitive ordering to the two characters.
Our pattern matcher will create a branch whenever a matching character is found after a "zero or more" character, so ensuring that the "zero or more" character is at the end means that we can reduce at least one branch (that would have come from the "single match" character).

With these two rules, we are able to find matching duplicates and prevent their insertion.
These rules also have another side-effect, in that they grant us the ability to determine if a given match expression matches a strict subset of another expression.
This is accomplished by using a match expression as the input of another expression, and then checking that the expression's length is smaller.
This is used in several ways, such as when creating new branches (to prevent adding unnecessary new entries if an existing entry already encompasses the would-be entry), and also when ensuring that a user with the `admin` permission may modify the correct entries.

## Using the Tables

The branch permissions system tables, `dolt_branch_control` and `dolt_branch_namespace_control`, are both built on top of [users and privileges](/reference/server/access-management) system.

### Default State

When the `dolt_branch_control` table is first created, the following statement executes on it: `INSERT INTO dolt_branch_control VALUES ('%', '%', '%', '%', 'write');`.
This allows all users to freely modify all branches.
They can not, however, modify the system tables.

When the `dolt_branch_namespace_control` table is first created, it is empty.
This allows all users to freely create a branch with any name.

### Editing the System Tables

The modification of both system tables are controlled by two entities: the privileges system and the `dolt_branch_control` table itself.
In Doltgres, modifying the branch control system tables requires a role with the `SUPERUSER` attribute (such as the default `postgres` user).
A superuser may edit any entry in either table, including entries containing special characters.

It is important to note that superusers do **not** have an implicit permission to modify branches.
They must insert their own row if they do not match a pre-existing row on their desired database and branch.
This ensures that the table is the single source-of-truth regarding which users may modify branches.

In addition to the above privileges, if a user has the `admin` permission, then that user may edit any entries in either system table that they either directly match, or their database and branch are supersets of the target entries (unless there is a more specific rule, which is further discussed below).

### Branch Modification

All users may read any branch.
The branch permissions tables primarily affect modification.
When a user (connected via a client to a Doltgres instance running as a server) attempts any operation that may modify either the branch or its contents (tables, staged work, etc.), then the first system table, `dolt_branch_control`, is invoked.

To find all matching entries, we start with the global set of all entries.
We first match against the database, which (hopefully) reduces the set of entries.
Next we match against the branch, reducing the set further still.
We repeat the same process for the user name and host, which gives us our final set.
Out of the remaining entries, we filter them down to which entries are the most specific for that branch (e.g. `ab%` vs `abcd`), gather all of the permissions from the filtered set, and then check that the user has the required permissions to execute the desired statement.
If not, an error message is thrown.

This same process is also used when attempting to modify the system tables, except that there's an additional check for the user's privileges.
If they have the necessary privileges, then we skip the step where we match entries.

### Branch Creation

The `dolt_branch_namespace_control` only applies when a new branch is being created.
Any user may freely read from any branch and also create a new branch.
They may be restricted in the name that they're able to choose, though.

The process of determining whether a user may create a branch is broken into two sections.
In the first, we start with the global set of all entries, and retain all entries that match both the database and branch.
If this set is empty, then we **allow** the branch creation.
If this set is not empty, then we continue, matching the user and host.
If this final set is empty, then we **reject** the branch creation. However, if the final set is not empty, then we allow the branch creation.

After the branch has been created, we add a new entry to `dolt_branch_control` only if that entry would not be a subset of an existing entry with an `admin` permission.
This is to reduce duplicate entries as best we can in the table.
The new entry will exactly match all of the details of its creator, meaning that no special characters will be used.
This entry will also contain the `admin` permission, as the branch creator has full permission to modify their branch, as well as allowing others to modify their branch by adding new relevant entries to the system tables.
No entry is added to `dolt_branch_namespace_control`, as branches may not have duplicate names.

### Longest Match

For both `dolt_branch_control` and `dolt_branch_namespace_control`, we only consider the entry set that has the longest matching branch expressions.
This is so that the set contains the most specific entries to the target branch and user.
This matching occurs _before_ the user and host are checked (the database is ignored when looking at the longest match), meaning a longer entry effectively creates a new restricted space.
Because we [fold all of our match expressions](#pattern-matching), we can guarantee that all longer matches are a subset of shorter matches.
For example, `ab%` is shorter than `abc%`, and consequently `abcd` is a subset of `ab%`.
This does leave the case where matches of equivalent length may still be a superset/subset combo (such as `abc_` and `abcd`), however we treat them as having an equivalent specificity.

### Additional Branch Creation Considerations

It is worth noting that operations such as renaming a branch also require the correct permissions on `dolt_branch_control`, or the correct privileges to be an admin.
This is because a rename may be viewed as a copy and delete, therefore it is modifying the original branch.

To turn `dolt_branch_namespace_control` into a blacklist (just like `dolt_branch_control`), then run the following statement:

```sql
INSERT INTO dolt_branch_namespace_control VALUES ('%', '%', '', '');
```

This will add an entry that will match every possible branch, but will never match a user as a user will never have an empty user and host.
Due to the longest match rule, this entry will be ignored when a valid match is found.

## Storage

All data related to branch permissions is stored in the file `branch_control.db` under the dolt configuration directory (defaults to `.doltcfg`).
The location of this file can be changed with the `branch_control_file` key in the [YAML config](/reference/server/configuration), similar to the `auth_file` key described in [access management](/reference/server/access-management).

## Binlog

Currently, all operations are written to a binlog that is stored alongside the system tables.
There are no ways of accessing the binlog for now, but in the future support will be added.
The binlog is intended for correcting mistakes, as well as providing history on how the system tables have changed.

## Examples

The following examples are a small snippet that shows branch permissions in action.
It is assumed that this document has been read in full, as concepts that are explained in previous sections are not explained in-depth.
The [setup section](#setup) is run before each example, therefore remember to have a dedicated terminal window for [setup](#setup) if you want to try any of these examples yourself.
All examples other than [setup](#setup) will exclusively use the second terminal window.
All examples will use Postgres' default client, `psql`.
Feel free to use your desired Postgres client.

### Setup

This handles starting the server, along with creating the database and users used in the examples.
As we are running these examples locally, we will use two terminal windows.
The first window will contain the server, which we start by running `doltgres`.
It is worth noting that the examples use the default host and port of `localhost:5432`.
If these are already in use for your system, then you may change them with the `listener.host` and `listener.port` fields in a [config.yaml file](/reference/server/configuration).

As explained in the [default state section](#default-state), we automatically add a row to the `dolt_branch_control` table that allows all users to modify all branches by default.
For these examples, we remove that default row.
This allows us to demonstrate the desired functionality a bit more easily.

The first time the server runs, it creates a superuser named `postgres` (with the password `password`), and we will be taking advantage of this user in these examples.
We also, however, want a user that is _not_ a superuser, and is more representative of a standard user.
We name that user `testuser` in the examples.
We grant `testuser` broad privileges so that we do not have to worry about assigning privileges to allow for basic table operations, however they are still not a superuser, and therefore may not edit the branch control system tables directly.
[You may read more about this behavior in an earlier section.](#editing-the-system-tables)

In the second terminal window, connect as `postgres` and run the setup statements:

```sql
$ psql -h localhost -U postgres
CREATE DATABASE example;
\c example
DELETE FROM dolt_branch_control;
CREATE USER testuser PASSWORD 'pass';
GRANT ALL PRIVILEGES ON SCHEMA public TO testuser;
```

### The `write` Permission

Please refer to the [setup section](#setup) before continuing this example.
This example shows the `write` permission in action.
We add the `write` permission to the `testuser` user, which allows that user to modify the contents of our `main` (default) branch, while the `postgres` user does not have the permission and cannot make any modifications.

```sql
$ psql -h localhost -U postgres example
INSERT INTO dolt_branch_control VALUES ('%', 'main', 'testuser', '%', 'write');
CREATE TABLE test (pk BIGINT PRIMARY KEY);
ERROR:  `postgres`@`127.0.0.1` does not have the correct permissions on branch `main`

$ psql -h localhost -U testuser example
CREATE TABLE test (pk BIGINT PRIMARY KEY);
```

### The `admin` Permission

Please refer to the [setup section](#setup) before continuing this example.
This example shows the `admin` permission in action.
`admin` functions similarly to the `write` permission, however it also allows the user to `INSERT`/`UPDATE`/`DELETE` entries that match the database and branch (or the resulting set of potential matches from the database and branch match expressions are a subset of the one that contains the `admin` permission).
We show this by demonstrating that `testuser` cannot modify the `main` (default) branch at first, nor can they modify the `dolt_branch_control` and `dolt_branch_namespace_control` tables.
We then switch to `postgres` (who is a [superuser](#editing-the-system-tables)) and give `testuser` an `admin` permission over the `main%` branch.
The [special "zero or more" character](#pattern-matching) means that they may add additional entries of `main`, as well as other branches that begin with `main`.
The users added are all fake, and are just used to demonstrate the capability.
We end by showing that this only applies to the exact match expression, as the very similar `_main` branch name is still off-limits.

```sql
$ psql -h localhost -U testuser example
CREATE TABLE test (pk BIGINT PRIMARY KEY);
ERROR:  `testuser`@`127.0.0.1` does not have the correct permissions on branch `main`
INSERT INTO dolt_branch_control VALUES ('example', 'main', 'newuser', '%', 'write');
ERROR:  `testuser`@`127.0.0.1` cannot add the row ["example", "main", "newuser", "%", "write"]
INSERT INTO dolt_branch_namespace_control VALUES ('example', 'main', 'newuser', '%');
ERROR:  `testuser`@`127.0.0.1` cannot add the row ["example", "main", "newuser", "%"]

$ psql -h localhost -U postgres example
INSERT INTO dolt_branch_control VALUES ('example', 'main%', 'testuser', '%', 'admin');

$ psql -h localhost -U testuser example
CREATE TABLE test (pk BIGINT PRIMARY KEY);
INSERT INTO dolt_branch_control VALUES ('example', 'main', 'newuser', '%', 'write');
INSERT INTO dolt_branch_control VALUES ('example', 'main_new', 'otheruser', '%', 'write');
INSERT INTO dolt_branch_control VALUES ('example', '_main', 'someuser', '%', 'write');

INSERT INTO dolt_branch_namespace_control VALUES ('example', 'main1', 'theuser', '%');
INSERT INTO dolt_branch_namespace_control VALUES ('example', '_main', 'anotheruser', '%');
```

### Restricting Branch Names

Please refer to the [setup section](#setup) before continuing this example. This example shows how
to [restrict which users are able to use branch names](#branch-creation) with the `main` prefix. To
do this, we insert a `main%` entry into the `dolt_branch_namespace_control` table, assigning the
`testuser` user. We create another entry with `mainroot%` as the branch name, and assign that to
`postgres`. This means that `postgres` is able to create any branches with names that **do not**
start with `main`, but is unable to create branches that **do** start with `main`. The exception
being `mainroot`, which while having `main` as a prefix, it is considered [the longest
match](#longest-match), and therefore takes precedence over the `main%` entry. Consequently,
`testuser` cannot use `mainroot` as a prefix, as [the longest match](#longest-match) overrides their
`main%` entry.

```sql
$ psql -h localhost -U postgres example
INSERT INTO dolt_branch_namespace_control VALUES ('%', 'main%', 'testuser', '%');
INSERT INTO dolt_branch_namespace_control VALUES ('%', 'mainroot%', 'postgres', '%');
SELECT DOLT_BRANCH('does_not_start_with_main');
 dolt_branch
-------------
           0
(1 row)

SELECT DOLT_BRANCH('main1');
ERROR:  `postgres`@`127.0.0.1` cannot create a branch named `main1`
SELECT DOLT_BRANCH('mainroot');
 dolt_branch
-------------
           0
(1 row)

example=# \q

$ psql -h localhost -U testuser example
SELECT DOLT_BRANCH('main1');
 dolt_branch
-------------
           0
(1 row)

SELECT DOLT_BRANCH('mainroot1');
ERROR:  `testuser`@`127.0.0.1` cannot create a branch named `mainroot1`
```

### Multiple Databases

Please refer to the [setup section](#setup) before continuing this example.
This example simply shows how an entry in each system table is scoped to a database.
Our pre-existing database is `example`, which we created in the [setup section](#setup).
Therefore, we create another database named `newdb`, which the user `postgres` will not have any permissions on.

```
$ psql -h localhost -U postgres example
CREATE TABLE test (pk BIGINT PRIMARY KEY);
ERROR:  `postgres`@`127.0.0.1` does not have the correct permissions on branch `main`
INSERT INTO dolt_branch_control VALUES ('example', '%', 'postgres', '%', 'write');
CREATE TABLE test (pk BIGINT PRIMARY KEY);
DROP TABLE test;
CREATE DATABASE newdb;
\c newdb
CREATE TABLE test2 (pk BIGINT PRIMARY KEY);
```
