Files
2026-07-13 10:08:59 +00:00

39 KiB
Raw Permalink Blame History

Note

本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
English · 原始项目 · 上游 README
原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。

Dolt 是数据的 Git

Dolt 是一款 SQL 数据库,你可以像操作 Git 仓库一样对它进行 fork、clone、branch、merge、push 和 pull。

像连接任何 MySQL 数据库一样连接 Dolt,即可读取或修改 schema 和数据。版本控制功能通过 SQL 中的系统表、函数和存储过程暴露出来。

或者,使用类似 Git 的命令行界面导入 CSV 文件、提交更改、推送到远程,或合并队友的更改。你熟悉的所有 Git 命令在 Dolt 中用法完全相同。

Git 对文件进行版本控制。Dolt 对表进行版本控制。它就像 Git 和 MySQL 的结合体。

我们还构建了 DoltHub,,一个分享 Dolt 数据库的平台。我们免费托管公开数据。如果你想自行托管 DoltHub,我们有 DoltLab.。如果你想让我们为你运行 Dolt 服务器,我们有 Hosted Dolt.。

更喜欢 Postgres 而不是 MySQL?试试 Doltgres,,目前已进入 Beta 版本。

加入我们的 Discord打个招呼、提问,或查看我们的路线图,了解我们接下来要构建什么。

视频介绍

Dolt Explainer Video

它有什么用?

用途很多!Dolt 是一款通用工具,应用场景数不胜数。但如果你想找些灵感,可以看看人们目前是如何使用它的.。

Dolt 为 BeadsGas Town. 提供支持。它是智能体记忆(agent memory)的最佳数据库,尤其是在你迈向多智能体、多机器工作流时。

Dolt CLI

dolt CLI 拥有与 git 相同的命令,并附带一些额外功能。

$ dolt
Valid commands for dolt are
                init - Create an empty Dolt data repository.
              status - Show the working tree status.
                 add - Add table changes to the list of staged table changes.
                diff - Diff a table.
               reset - Remove table changes from the list of staged table changes.
               clean - Remove untracked tables from working set.
              commit - Record changes to the repository.
                 sql - Run a SQL query against tables in repository.
          sql-server - Start a MySQL-compatible server.
                 log - Show commit logs.
              branch - Create, list, edit, delete branches.
            checkout - Checkout a branch or overwrite a table from HEAD.
               merge - Merge a branch.
           conflicts - Commands for viewing and resolving merge conflicts.
         cherry-pick - Apply the changes introduced by an existing commit.
              revert - Undo the changes introduced in a commit.
               clone - Clone from a remote data repository.
               fetch - Update the database from a remote data repository.
                pull - Fetch from a dolt remote data repository and merge.
                push - Push to a dolt remote.
              config - Dolt configuration.
              remote - Manage set of tracked repositories.
              backup - Manage a set of server backups.
               login - Login to a dolt remote host.
               creds - Commands for managing credentials.
                  ls - List tables in the working set.
              schema - Commands for showing and importing table schemas.
               table - Commands for copying, renaming, deleting, and exporting tables.
                 tag - Create, list, delete tags.
               blame - Show what revision and author last modified each row of a table.
         constraints - Commands for handling constraints.
             migrate - Executes a database migration to use the latest Dolt data format.
         read-tables - Fetch table(s) at a specific commit into a new dolt repo
                  gc - Cleans up unreferenced data from the repository.
       filter-branch - Edits the commit history using the provided query.
          merge-base - Find the common ancestor of two commits.
             version - Displays the current Dolt cli version.
                dump - Export all tables in the working set into a file.

安装

Dolt 是一个约 103 MB 的单一程序。

dolt $ du -h /Users/timsehn/go/bin/dolt
103M	/Users/timsehn/go/bin/dolt

安装非常简单。下载后放到你的 PATH 上即可。我们还为大多数平台提供了多种更便捷的方式。

从最新版本安装

要在基于 Linux 或 Mac 的系统上安装,请在终端中运行以下命令:

sudo bash -c 'curl -L https://github.com/dolthub/dolt/releases/latest/download/install.sh | bash'

这将下载最新的 dolt 版本,并放到 /usr/local/bin/ 中,该路径很可能已在你的 $PATH 中。

安装脚本需要 sudo 权限,以便将 dolt 放到 /usr/local/bin 中。如果你没有 root 权限,或不愿以 root 权限运行脚本,可以从最新版本,)下载适用于你平台的 dolt 二进制文件,解压后,将二进制文件放到 $PATH 上的某个位置。

Linux

Arch Linux

Dolt 已收录在 Arch Linux 的官方软件仓库中。

pacman -S dolt

Mac

Homebrew

Dolt 已上架 Homebrew,每个版本发布时都会更新。

brew install dolt

MacPorts

在 macOS 上,也可以通过 MacPorts:) 的社区维护 port) 安装 Dolt。

sudo port install dolt

Windows

releases) 中下载最新的 Microsoft Installer.msi 文件)并运行。

有关在 Windows 上运行的信息,请参见此处.。

Chocolatey

你可以使用 Chocolatey:) 安装 dolt

choco install dolt

Docker

Dolt 提供以下官方 Docker 镜像:

从源码构建

请确保已安装 Go,且 go 在你的 path 中。Dolt 依赖 cgo,),因此你还需要可用的 C 编译器和工具链。

克隆此仓库并进入 go 目录。然后运行:

go install ./cmd/dolt

输出将位于 $GOPATH/bin,默认值为 ~/go/bin。要测试你的构建,请尝试:

~/go/bin/dolt version

配置

在终端中运行 dolt,验证安装是否成功。

$ dolt
Valid commands for dolt are
[...]

使用你的用户名和邮箱配置 dolt,创建提交时需要这些信息。命令用法与 git 完全相同。

$ dolt config --global --add user.email YOU@DOMAIN.COM
$ dolt config --global --add user.name "YOUR NAME"

入门

导航到你想存放数据的目录

Dolt 需要一个位置来存储你的数据库。我将把数据库放在 ~/dolt

% cd ~
% mkdir dolt
% cd dolt

你创建的任何数据库都会存储在此目录中。因此,在本示例中,运行 create database getting_started 后,将在此处创建一个名为 getting_started 的目录。进入 ~/dolt/getting_started 后,即可使用 Dolt 命令行访问该数据库。

注意:在本示例中,getting_started 目录将在你在 Create a schema section 的 SQL shell 中运行 create database getting_started; 后创建。目前只需创建目录并进入即可,不要执行其他操作。

启动兼容 MySQL 的数据库服务器

Dolt 内置了一个与 MySQL 兼容的数据库服务器。要启动它,请使用命令 dolt sql-server。运行该命令后,服务器会在 3306 端口启动。

dolt sql-server
Starting server with Config HP="localhost:3306"|T="28800000"|R="false"|L="info"

此时终端会停在那里不动。这表示服务器正在运行。任何错误都会打印在这个终端中。让它保持运行,并打开一个新的终端。

使用 MySQL 客户端连接(最高支持 8.4 版本)

在新的终端中,我们将使用客户端连接到正在运行的数据库服务器。Dolt 也自带了一个与 MySQL 兼容的客户端。

% dolt -u root -p "" sql
# Welcome to the Dolt MySQL client.
# Statements must be terminated with ';'.
# "exit" or "quit" (or Ctrl-D) to exit.
mysql>

在运行 dolt sql-server 的另一个终端中,你会看到以下日志行。

2022-06-06T13:14:32-07:00 INFO [conn 1] NewConnection {DisableClientMultiStatements=false}

你已经连接成功!

趁这个机会,我们先安装一份 MySQL,以便使用该客户端进行连接。请前往 MySQL Getting Started 文档,在你的机器上安装 MySQL。我在 Mac 上使用 Homebrew 安装 MySQLbrew install mysql@8.4。或者,你也可以通过运行 brew install mysql-client@8.4 仅安装客户端组件。

注意:请确保安装的是 MySQL 8.4 版本。MySQL 8.4 是当前长期支持(Long Term SupportLTS)版本,也就是说它是 MySQL 稳定且受支持的版本。MySQL 9.0 也可获得,但属于“创新”(innovation)版本,意味着它包含更多最新变更和功能,但可能不如 LTS 版本稳定。9.0 版本更改了认证支持,默认情况下无法连接到 Dolt SQL 服务器。你可以通过运行 brew install mysql@8.4 用 Homebrew 安装 MySQL 8.4。如果你确实想使用 MySQL 9.0,请阅读我们关于如何为 caching_sha2_password 认证配置 Dolt 的文章.

MySQL 附带一个名为 mysqld 的 MySQL 服务器和一个名为 mysql 的 MySQL 客户端。你只需关注客户端。按照 MySQL 文档中的说明操作后,请确保你的路径上有 mysql 客户端:

% mysql --version
mysql  Ver 8.0.29 for macos12.2 on x86_64 (Homebrew)

现在,要将 mysql 客户端连接到 Dolt,你需要通过传入主机和端口,强制 MySQL 客户端走 TCP 接口。默认使用的是 socket 接口,Dolt 也支持该接口,但仅在 localhost 上可用。因此,更好的做法是演示 TCP 接口。MySQL 客户端还要求你指定用户,此处为 root

% mysql --host 127.0.0.1 --port 3306 -uroot
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.9-Vitess 

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

同样,为了确认客户端确实已连接,你应该在 dolt sql-server 终端中看到以下内容

2022-06-06T13:26:55-07:00 INFO [conn 2] NewConnection {DisableClientMultiStatements=false}

如你所见,Dolt 支持任何与 MySQL 兼容的客户端。Dolt 自带客户端,但你可以使用任何 MySQL 客户端,例如 MySQL 自带的那个。

创建 schema

现在我们终于可以做些有意思的事了。我会留在 mysql 客户端中,执行以下 SQL 语句来创建一个名为 getting_started 的数据库。getting_started 数据库将包含三张表:employeesteamsemployees_teams

mysql> create database getting_started;
Query OK, 1 row affected (0.04 sec)

mysql> use getting_started;
Database changed
mysql> create table employees (
    id int, 
    last_name varchar(255), 
    first_name varchar(255), 
    primary key(id));
Query OK, 0 rows affected (0.01 sec)

mysql> create table teams (
    id int, 
    team_name varchar(255), 
    primary key(id)); 
Query OK, 0 rows affected (0.00 sec)

mysql> create table employees_teams(
    team_id int, 
    employee_id int, 
    primary key(team_id, employee_id), 
    foreign key (team_id) references teams(id), 
    foreign key (employee_id) references employees(id));
Query OK, 0 rows affected (0.01 sec)

mysql> show tables;
+---------------------------+
| Tables_in_getting_started |
+---------------------------+
| employees                 |
| employees_teams           |
| teams                     |
+---------------------------+
3 rows in set (0.00 sec)

Dolt 支持外键、二级索引、触发器、检查约束和存储过程。它是一个功能丰富的现代 SQL 数据库。

创建 Dolt commit

是时候使用你的第一个 Dolt 功能了。我们将创建一个 Dolt commit. Dolt commit 允许你进行时间旅行并查看血缘关系。每当你想恢复到这一时间点或与之进行比较时,就创建一个 Dolt commit。

Dolt 通过类似 Git 的界面暴露版本控制功能。在命令行中,Dolt 命令与对应的 Git 命令一一映射,只是目标对象从文件变成了表。在 SQL 中,Dolt 将版本控制的读操作暴露为系统表,将版本控制的写操作暴露为存储过程.

系统表和存储过程的命名遵循 dolt_<command> 模式。因此,CLI 中的 dolt add 会变成存储过程 dolt_add。传递选项也遵循命令行模型。例如,要指定要添加的表,请将表名作为选项传给 dolt_add 存储过程。对于命名参数,例如向 dolt_commit 命令发送消息,请按顺序使用两个参数,如 ('-m', 'This is a message')。如果你熟悉 Git,这些版本控制存储过程和系统表应该会感觉很熟悉。

那么,我们像这样添加并提交新 schema。

mysql> call dolt_add('teams', 'employees', 'employees_teams');
+--------+
| status |
+--------+
|      0 |
+--------+
1 row in set (0.03 sec)

mysql> call dolt_commit('-m', 'Created initial schema');
+----------------------------------+
| hash                             |
+----------------------------------+
| ne182jemgrlm8jnjmoubfqsstlfi1s98 |
+----------------------------------+
1 row in set (0.02 sec)

mysql> select * from dolt_log;
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| commit_hash                      | committer | email           | date                    | message                    |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema     |
| vluuhvd0bn59598utedt77ed9q5okbcb | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:33:59.531 | Initialize data repository |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
2 rows in set (0.01 sec)

就是这样。你的 schema 已创建,并且有一个 Dolt commit 在跟踪这次创建,可以在 dolt_log 系统表中看到。

请注意,Dolt commit 不同于标准 SQL 事务 COMMIT。在本例中,我启用了 AUTOCOMMIT 运行数据库,因此每条 SQL 语句都会自动生成事务 COMMIT。如果你希望系统为每个事务生成 Dolt commit,请使用系统变量 @@dolt_transaction_commit.

插入一些数据

现在,我要向数据库中填入 DoltHub 的几位员工。然后,我会把这些员工分配到两个团队:工程(engineering)和销售(sales)。在初创公司里,CEO 身兼数职,所以他会同时被分配到多个团队。

mysql> insert into employees values 
    (0, 'Sehn', 'Tim'), 
    (1, 'Hendriks', 'Brian'), 
    (2, 'Son','Aaron'), 
    (3, 'Fitzgerald', 'Brian');
Query OK, 4 rows affected (0.01 sec)

mysql> select * from employees where first_name='Brian';
+------+------------+------------+
| id   | last_name  | first_name |
+------+------------+------------+
|    1 | Hendriks   | Brian      |
|    3 | Fitzgerald | Brian      |
+------+------------+------------+
2 rows in set (0.00 sec)

mysql> insert into teams values 
    (0, 'Engineering'), 
    (1, 'Sales');
Query OK, 2 rows affected (0.00 sec)

mysql> insert into employees_teams values 
    (0,0), 
    (1,0), 
    (2,0), 
    (0,1), 
    (3,1);
ERROR 1452 (HY000): cannot add or update a child row - Foreign key violation on fk: `rv9ek7ft`, table: `employees_teams`, referenced table: `teams`, key: `[2]`

哎呀,我违反了约束。看来我创建表时把 teams 放在 employees 前面了。插入时应该始终明确指定列,而不要依赖自然顺序。活该!Dolt 具备现代 SQL 关系型数据库的全部能力,可确保数据完整性。

mysql> insert into employees_teams(employee_id, team_id) values 
    (0,0), 
    (1,0), 
    (2,0), 
    (0,1), 
    (3,1);
Query OK, 5 rows affected (0.01 sec)

mysql> select first_name, last_name, team_name from employees 
    join employees_teams on (employees.id=employees_teams.employee_id) 
    join teams on (teams.id=employees_teams.team_id) 
    where team_name='Engineering';
+------------+-----------+-------------+
| first_name | last_name | team_name   |
+------------+-----------+-------------+
| Tim        | Sehn      | Engineering |
| Brian      | Hendriks  | Engineering |
| Aaron      | Son       | Engineering |
+------------+-----------+-------------+
3 rows in set (0.00 sec)

看起来一切都已正确插入。我能够用那个三表 JOIN 列出工程团队的成员。Dolt 最多支持十二表 JOINs。再说一次,Dolt 是现代 SQL 关系型数据库,并配有 Git 风格的版本控制。

查看 diff

现在,如果你想在提交之前查看工作区里有哪些变更,可以使用 dolt_statusdolt_diff_<tablename> 系统表。

mysql> select * from dolt_status;
+-----------------+--------+----------+
| table_name      | staged | status   |
+-----------------+--------+----------+
| teams           |      0 | modified |
| employees       |      0 | modified |
| employees_teams |      0 | modified |
+-----------------+--------+----------+
3 rows in set (0.01 sec)

mysql> select * from dolt_diff_employees;
+--------------+---------------+-------+-----------+----------------+----------------+-----------------+---------+----------------------------------+-------------------------+-----------+
| to_last_name | to_first_name | to_id | to_commit | to_commit_date | from_last_name | from_first_name | from_id | from_commit                      | from_commit_date        | diff_type |
+--------------+---------------+-------+-----------+----------------+----------------+-----------------+---------+----------------------------------+-------------------------+-----------+
| Sehn         | Tim           |     0 | WORKING   | NULL           | NULL           | NULL            |    NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added     |
| Hendriks     | Brian         |     1 | WORKING   | NULL           | NULL           | NULL            |    NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added     |
| Son          | Aaron         |     2 | WORKING   | NULL           | NULL           | NULL            |    NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added     |
| Fitzgerald   | Brian         |     3 | WORKING   | NULL           | NULL           | NULL            |    NULL | ne182jemgrlm8jnjmoubfqsstlfi1s98 | 2022-06-07 16:35:49.277 | added     |
+--------------+---------------+-------+-----------+----------------+----------------+-----------------+---------+----------------------------------+-------------------------+-----------+
4 rows in set (0.00 sec)

从 diff 可以看出,我已向 employees 表添加了正确的值。这些值之前是 NULL,现在已填充完成。

最后再来一次 Dolt 提交,这次用 -am 添加所有受影响的表。

mysql> call dolt_commit('-am', 'Populated tables with data');
+----------------------------------+
| hash                             |
+----------------------------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 |
+----------------------------------+
1 row in set (0.02 sec)

你可以用 dolt_log 检查日志,并用不带作用域的 dolt_diff 查看每次提交中哪些表发生了变更。不带作用域的 dolt_diff 会告诉你该次提交中该表的 schema、data 或二者是否发生了变化。

mysql> select * from dolt_log;
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| commit_hash                      | committer | email           | date                    | message                    |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema     |
| vluuhvd0bn59598utedt77ed9q5okbcb | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:33:59.531 | Initialize data repository |
+----------------------------------+-----------+-----------------+-------------------------+----------------------------+
3 rows in set (0.00 sec)

mysql> select * from dolt_diff;
+----------------------------------+-----------------+-----------+-----------------+-------------------------+----------------------------+-------------+---------------+
| commit_hash                      | table_name      | committer | email           | date                    | message                    | data_change | schema_change |
+----------------------------------+-----------------+-----------+-----------------+-------------------------+----------------------------+-------------+---------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | teams           | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data |           1 |             0 |
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | employees       | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data |           1 |             0 |
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | employees_teams | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data |           1 |             0 |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | employees       | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema     |           0 |             1 |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | employees_teams | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema     |           0 |             1 |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | teams           | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema     |           0 |             1 |
+----------------------------------+-----------------+-----------+-----------------+-------------------------+----------------------------+-------------+---------------+
6 rows in set (0.00 sec)

糟了!我犯了个错误。

Dolt 支持通过 call dolt_reset() 撤销变更。假设我不小心删了一张表。

mysql> drop table employees_teams;
Query OK, 0 rows affected (0.01 sec)

mysql> show tables;
+---------------------------+
| Tables_in_getting_started |
+---------------------------+
| employees                 |
| teams                     |
+---------------------------+
2 rows in set (0.00 sec)

在传统数据库中,这可能会带来灾难性后果。在 Dolt 中,你只需一条命令就能恢复表。

mysql> call dolt_reset('--hard');
+--------+
| status |
+--------+
|      0 |
+--------+
1 row in set (0.01 sec)

mysql> show tables;
+---------------------------+
| Tables_in_getting_started |
+---------------------------+
| employees                 |
| employees_teams           |
| teams                     |
+---------------------------+
3 rows in set (0.01 sec)

Dolt 让数据库运维更少出错。你随时可以回滚进行中的更改,或回溯到已知的良好状态。你还可以使用 dolt_revert(). 撤销特定提交。即使你意外在错误的数据库上运行了 drop databaseDolt 也允许你通过调用 dolt_undrop() stored procedure. 来撤销该操作。

在 SQL Workbench 中查看数据

讨厌命令行?让我们使用 Tableplus 进行一些修改。Tableplus 是一款免费的 SQL Workbench。请按照其官网的安装说明进行操作。

现在,要连接数据库,你必须选择 MySQL 作为连接类型。然后为连接输入一个名称,将 getting_started 作为数据库,将 root 作为用户。

Tableplus Connection

点击连接后,你将看到一个熟悉的数据库 workbench GUI。

Tableplus

在分支上进行更改

要在分支上进行更改,我使用 dolt_checkout() 存储过程。使用 -b 选项会创建分支,就像在 Git 中一样。

Tableplus 让我可以在 SQL 选项卡中输入多行 SQL 脚本。我输入了以下 SQL,用于检出分支、更新、插入、删除,最后 Dolt commit 我的更改。

call dolt_checkout('-b','modifications');
update employees SET first_name='Timothy' where first_name='Tim';
insert INTO employees (id, first_name, last_name) values (4,'Daylon', 'Wilkins');
insert into employees_teams(team_id, employee_id) values (0,4);
delete from employees_teams where employee_id=0 and team_id=1;
call dolt_commit('-am', 'Modifications on a branch');

以下是 Tableplus 中的结果。

New Updates

回到终端后,我看不到在 Tableplus 中所做的表修改,因为这些更改发生在与我当前会话中检出的分支不同的分支上。

mysql> select * from dolt_branches;
+---------------+----------------------------------+------------------+------------------------+-------------------------+----------------------------+
| name          | hash                             | latest_committer | latest_committer_email | latest_commit_date      | latest_commit_message      |
+---------------+----------------------------------+------------------+------------------------+-------------------------+----------------------------+
| main          | 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn         | tim@dolthub.com        | 2022-06-07 16:39:32.066 | Populated tables with data |
| modifications | uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim Sehn         | tim@dolthub.com        | 2022-06-07 16:41:49.847 | Modifications on a branch  |
+---------------+----------------------------------+------------------+------------------------+-------------------------+----------------------------+
2 rows in set (0.00 sec)

mysql> select active_branch();
+-----------------+
| active_branch() |
+-----------------+
| main            |
+-----------------+
1 row in set (0.00 sec)

mysql> select * from employees;
+------+------------+------------+
| id   | last_name  | first_name |
+------+------------+------------+
|    0 | Sehn       | Tim        |
|    1 | Hendriks   | Brian      |
|    2 | Son        | Aaron      |
|    3 | Fitzgerald | Brian      |
+------+------------+------------+
4 rows in set (0.00 sec)

无论当前检出的是哪个分支,我都可以使用 SQL as of 语法查询该分支。

mysql> select * from employees as of 'modifications';
+------+------------+------------+
| id   | last_name  | first_name |
+------+------------+------------+
|    0 | Sehn       | Timothy    |
|    1 | Hendriks   | Brian      |
|    2 | Son        | Aaron      |
|    3 | Fitzgerald | Brian      |
|    4 | Wilkins    | Daylon     |
+------+------------+------------+
5 rows in set (0.01 sec)

如果我想查看两个分支之间的 diff,可以使用 dolt_diff() 表函数。它接受两个分支和表名作为参数。

mysql> select * from dolt_diff('main', 'modifications', 'employees');
+--------------+---------------+-------+---------------+-------------------------+----------------+-----------------+---------+-------------+-------------------------+-----------+
| to_last_name | to_first_name | to_id | to_commit     | to_commit_date          | from_last_name | from_first_name | from_id | from_commit | from_commit_date        | diff_type |
+--------------+---------------+-------+---------------+-------------------------+----------------+-----------------+---------+-------------+-------------------------+-----------+
| Sehn         | Timothy       |     0 | modifications | 2022-06-07 16:41:49.847 | Sehn           | Tim             |       0 | main        | 2022-06-07 16:39:32.066 | modified  |
| Wilkins      | Daylon        |     4 | modifications | 2022-06-07 16:41:49.847 | NULL           | NULL            |    NULL | main        | 2022-06-07 16:39:32.066 | added     |
+--------------+---------------+-------+---------------+-------------------------+----------------+-----------------+---------+-------------+-------------------------+-----------+
2 rows in set (0.00 sec)

如你所见,借助 Dolt,你可以在 SQL 数据库中获得 Git 风格分支和 diff 的全部能力。

在另一个分支上进行 schema 更改

我也可以在分支上进行 schema 更改,以便对新 schema 进行隔离测试。我将在新分支上添加 start_date 列并填充数据。

mysql> call dolt_checkout('-b', 'schema_changes');
+--------+
| status |
+--------+
|      0 |
+--------+
1 row in set (0.01 sec)

mysql> alter table employees add column start_date date;
Query OK, 0 rows affected (0.02 sec)

mysql> update employees set start_date='2018-09-08';
Query OK, 4 rows affected (0.01 sec)
Rows matched: 4  Changed: 4  Warnings: 0

mysql> update employees set start_date='2021-04-19' where last_name='Fitzgerald';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from employees;
+------+------------+------------+------------+
| id   | last_name  | first_name | start_date |
+------+------------+------------+------------+
|    0 | Sehn       | Tim        | 2018-09-08 |
|    1 | Hendriks   | Brian      | 2018-09-08 |
|    2 | Son        | Aaron      | 2018-09-08 |
|    3 | Fitzgerald | Brian      | 2021-04-19 |
+------+------------+------------+------------+
4 rows in set (0.00 sec)

mysql> call dolt_commit('-am', 'Added start_date column to employees');
+----------------------------------+
| hash                             |
+----------------------------------+
| pg3nfi0j1dpc5pf1rfgckpmlteaufdrt |
+----------------------------------+
1 row in set (0.01 sec)

在分支上更改 schema 为你提供了一种对新 schema 更改进行隔离集成测试的新方法。

全部合并

假设在 schema_changes 分支上对新 schema 的测试,以及在 modifications 分支上的数据测试都已顺利完成。是时候将所有编辑合并到 main 上了。这通过 dolt_merge 存储过程完成。

mysql> call dolt_checkout('main');
+--------+
| status |
+--------+
|      0 |
+--------+
1 row in set (0.01 sec)

mysql> select * from dolt_status;
Empty set (0.00 sec)

mysql> call dolt_merge('schema_changes');
+--------------+
| no_conflicts |
+--------------+
|            1 |
+--------------+
1 row in set (0.01 sec)

mysql> select * from employees;
+------+------------+------------+------------+
| id   | last_name  | first_name | start_date |
+------+------------+------------+------------+
|    0 | Sehn       | Tim        | 2018-09-08 |
|    1 | Hendriks   | Brian      | 2018-09-08 |
|    2 | Son        | Aaron      | 2018-09-08 |
|    3 | Fitzgerald | Brian      | 2021-04-19 |
+------+------------+------------+------------+
4 rows in set (0.00 sec)

Schema 变更成功。我们现在有了开始日期(start dates)。接下来进行数据变更。

mysql> call dolt_merge('modifications');
+--------------+
| no_conflicts |
+--------------+
|            1 |
+--------------+
1 row in set (0.02 sec)

mysql> select * from employees;
+------+------------+------------+------------+
| id   | last_name  | first_name | start_date |
+------+------------+------------+------------+
|    0 | Sehn       | Timothy    | 2018-09-08 |
|    1 | Hendriks   | Brian      | 2018-09-08 |
|    2 | Son        | Aaron      | 2018-09-08 |
|    3 | Fitzgerald | Brian      | 2021-04-19 |
|    4 | Wilkins    | Daylon     | NULL       |
+------+------------+------------+------------+
5 rows in set (0.00 sec)

数据变更也成功了。如你所见,我现在是 "Timothy" 而不是 "Tim"Daylon 已被添加,我们所有人都有开始日期,除了 Daylon——他是在另一个分支上添加的。

mysql> select first_name, last_name, team_name from employees 
    join employees_teams on (employees.id=employees_teams.employee_id) 
    join teams on (teams.id=employees_teams.team_id) 
    where team_name='Sales';
+------------+------------+-----------+
| first_name | last_name  | team_name |
+------------+------------+-----------+
| Brian      | Fitzgerald | Sales     |
+------------+------------+-----------+
1 row in set (0.01 sec)

我也离开了 Sales Team。Engineering 才是王道。

我必须提交所有更改,因为上次合并不是快进(fast-forward)合并。

mysql> call dolt_commit('-m', 'Merged all branches');
+----------------------------------+
| hash                             |
+----------------------------------+
| vn9b0qcematsj2f6ka0hfoflhr5s6p0b |
+----------------------------------+
1 row in set (0.01 sec)

mysql> select * from dolt_log;
+----------------------------------+-----------+-----------------+-------------------------+--------------------------------------+
| commit_hash                      | committer | email           | date                    | message                              |
+----------------------------------+-----------+-----------------+-------------------------+--------------------------------------+
| vn9b0qcematsj2f6ka0hfoflhr5s6p0b | Tim Sehn  | tim@dolthub.com | 2022-06-07 17:10:02.07  | Merged all branches                  |
| pg3nfi0j1dpc5pf1rfgckpmlteaufdrt | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:44:37.513 | Added start_date column to employees |
| uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:41:49.847 | Modifications on a branch            |
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:39:32.066 | Populated tables with data           |
| ne182jemgrlm8jnjmoubfqsstlfi1s98 | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:35:49.277 | Created initial schema               |
| vluuhvd0bn59598utedt77ed9q5okbcb | Tim Sehn  | tim@dolthub.com | 2022-06-07 16:33:59.531 | Initialize data repository           |
+----------------------------------+-----------+-----------------+-------------------------+--------------------------------------+
6 rows in set (0.00 sec)

现在,我们有了一个数据库,其中所有 schema 和数据变更都已合并,可以投入使用。

审计单元格血缘(Cell Lineage

是哪个 commit 更改了我的名字?使用 Dolt,你可以追踪数据库中每个单元格的血缘。让我们使用 dolt_history_<tablename>dolt_diff_<tablename> 来探索 Dolt 中的血缘功能。

dolt_history_<tablename> 会显示该行在每一个 commit 时的状态。

mysql> select * from dolt_history_employees where id=0 order by commit_date;
+------+-----------+------------+------------+----------------------------------+-----------+-------------------------+
| id   | last_name | first_name | start_date | commit_hash                      | committer | commit_date             |
+------+-----------+------------+------------+----------------------------------+-----------+-------------------------+
|    0 | Sehn      | Tim        | NULL       | 13qfqa5rojq18j84d1n2htjkm6fletg4 | Tim Sehn  | 2022-06-07 16:39:32.066 |
|    0 | Sehn      | Timothy    | NULL       | uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim Sehn  | 2022-06-07 16:41:49.847 |
|    0 | Sehn      | Tim        | 2018-09-08 | pg3nfi0j1dpc5pf1rfgckpmlteaufdrt | Tim Sehn  | 2022-06-07 16:44:37.513 |
|    0 | Sehn      | Timothy    | 2018-09-08 | vn9b0qcematsj2f6ka0hfoflhr5s6p0b | Tim Sehn  | 2022-06-07 17:10:02.07  |
+------+-----------+------------+------------+----------------------------------+-----------+-------------------------+
4 rows in set (0.00 sec)

dolt_diff_<tablename> 允许你将历史记录筛选为仅显示目标单元格发生变更的 commit。在这种情况下,我关心的是更改我名字的 commit。注意,有两个 commit 更改了我的名字,其中一个是原始变更,另一个是 merge commit。

mysql> select to_commit,from_first_name,to_first_name from dolt_diff_employees 
    where (from_id=0 or to_id=0) and (from_first_name <> to_first_name or from_first_name is NULL)
    order by to_commit_date;
+----------------------------------+-----------------+---------------+
| to_commit                        | from_first_name | to_first_name |
+----------------------------------+-----------------+---------------+
| 13qfqa5rojq18j84d1n2htjkm6fletg4 | NULL            | Tim           |
| uhkv57j4bp2v16vcnmev9lshgkqq8ppb | Tim             | Timothy       |
| vn9b0qcematsj2f6ka0hfoflhr5s6p0b | Tim             | Timothy       |
+----------------------------------+-----------------+---------------+
3 rows in set (0.01 sec)

Dolt 提供了强大的数据审计能力,可精确到单个单元格。数据库中的每个单元格随时间是如何、为何以及何时发生变更的?

延伸阅读

既然你已经对 Dolt 有了初步了解,请前往 我们的文档。你也可以在 我们的博客. 中了解我们一直在做什么。

安全策略

Dolt 当前的安全策略 维护在本仓库中。请按照其中的披露说明操作。请勿在本仓库的公开 GitHub Issues 中初次报告安全问题。

致谢与许可

Dolt 大量依赖来自 Noms 项目的开源代码和理念。我们非常感谢 Noms 团队免费提供这些代码, 没有它们,我们无法如此快速地构建 Dolt。

Dolt 采用 Apache License, Version 2.0 许可。详见 LICENSE