> [!NOTE]
> 本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
> [English](./README.en.md) · [原始项目](https://github.com/dolthub/dolt) · [上游 README](https://github.com/dolthub/dolt/blob/HEAD/README.md)
> 原作者、版权与许可证归属以原始项目及本仓库 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](https://www.dolthub.com),,一个分享 Dolt 数据库的平台。我们免费托管公开数据。如果你想自行托管 DoltHub,我们有 [DoltLab](https://www.doltlab.com).。如果你想让我们为你运行 Dolt 服务器,我们有 [Hosted Dolt](https://hosted.doltdb.com).。
更喜欢 Postgres 而不是 MySQL?试试 [Doltgres](https://github.com/dolthub/doltgresql),,目前已进入 Beta 版本。
[加入我们的 Discord](https://discord.com/invite/RFwfYpu)打个招呼、提问,或[查看我们的路线图](https://dolthub.com/docs/other/roadmap),了解我们接下来要构建什么。
# 视频介绍
[](https://www.youtube.com/watch?v=H2iZy0Cme10)
# 它有什么用?
用途很多!Dolt 是一款通用工具,应用场景数不胜数。但如果你想找些灵感,[可以看看人们目前是如何使用它的](https://dolthub.com/blog/2024-10-15-dolt-use-cases/).。
Dolt 为 [Beads](https://github.com/gastownhall/beads) 和 [Gas Town](https://github.com/steveyegge/gastown). 提供支持。它是智能体记忆(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 的单一程序。
```bash
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 权限运行脚本,可以从[最新版本](https://github.com/dolthub/dolt/releases),)下载适用于你平台的 dolt 二进制文件,解压后,将二进制文件放到 `$PATH` 上的某个位置。
### Linux
#### Arch Linux
Dolt 已收录在 Arch Linux 的官方软件仓库中。
```
pacman -S dolt
```
### Mac
#### Homebrew
Dolt 已上架 Homebrew,每个版本发布时都会更新。
```
brew install dolt
```
#### MacPorts
在 macOS 上,也可以通过 [MacPorts](https://www.macports.org):) 的[社区维护 port](https://ports.macports.org/port/dolt/)) 安装 Dolt。
```sh
sudo port install dolt
```
### Windows
在 [releases](https://github.com/dolthub/dolt/releases)) 中下载最新的 Microsoft Installer(`.msi` 文件)并运行。
有关在 Windows 上运行的信息,请参见[此处](https://dolthub.com/docs/introduction/installation/windows).。
#### Chocolatey
你可以使用 [Chocolatey](https://chocolatey.org/):) 安装 `dolt`。
```sh
choco install dolt
```
#### Docker
Dolt 提供以下官方 Docker 镜像:
* [`dolthub/dolt`](https://hub.docker.com/r/dolthub/dolt)):将 Dolt 作为 CLI 工具运行。
* [`dolthub/dolt-sql-server`](https://hub.docker.com/r/dolthub/dolt-sql-server)):以服务器模式运行 Dolt。
## 从源码构建
请确保已安装 Go,且 `go` 在你的 path 中。Dolt 依赖 [cgo](https://pkg.go.dev/cmd/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`。
```bash
% cd ~
% mkdir dolt
% cd dolt
```
你创建的任何数据库都会存储在此目录中。因此,在本示例中,运行 `create database getting_started` 后,将在此处创建一个名为 `getting_started` 的目录。进入 `~/dolt/getting_started` 后,即可使用 Dolt 命令行访问该数据库。
注意:在本示例中,`getting_started` 目录将在你在 [Create a schema section](#create-a-schema) 的 SQL shell 中运行 `create database getting_started;` 后创建。目前只需创建目录并进入即可,不要执行其他操作。
## 启动兼容 MySQL 的数据库服务器
Dolt 内置了一个与 MySQL 兼容的数据库服务器。要启动它,请使用命令 `dolt sql-server`。运行该命令后,服务器会在 3306 端口启动。
```bash
dolt sql-server
Starting server with Config HP="localhost:3306"|T="28800000"|R="false"|L="info"
```
此时终端会停在那里不动。这表示服务器正在运行。任何错误都会打印在这个终端中。让它保持运行,并打开一个新的终端。
## 使用 MySQL 客户端连接(最高支持 8.4 版本)
在新的终端中,我们将使用客户端连接到正在运行的数据库服务器。Dolt 也自带了一个与 MySQL 兼容的客户端。
```bash
% 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](https://dev.mysql.com/doc/mysql-getting-started/en/) 文档,在你的机器上安装 MySQL。我在 Mac 上使用 [Homebrew](https://brew.sh/) 安装 MySQL:`brew install mysql@8.4`。或者,你也可以通过运行 `brew install mysql-client@8.4` 仅安装客户端组件。
注意:请确保安装的是 MySQL 8.4 版本。MySQL 8.4 是当前长期支持(Long Term Support,LTS)版本,也就是说它是 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 的文章](https://www.dolthub.com/blog/2024-12-11-mysql9-and-caching-sha2-auth-support/).
MySQL 附带一个名为 `mysqld` 的 MySQL 服务器和一个名为 `mysql` 的 MySQL 客户端。你只需关注客户端。按照 MySQL 文档中的说明操作后,请确保你的路径上有 `mysql` 客户端:
```bash
% mysql --version
mysql Ver 8.0.29 for macos12.2 on x86_64 (Homebrew)
```
现在,要将 `mysql` 客户端连接到 Dolt,你需要通过传入主机和端口,强制 MySQL 客户端走 TCP 接口。默认使用的是 socket 接口,Dolt 也支持该接口,但仅在 `localhost` 上可用。因此,更好的做法是演示 TCP 接口。MySQL 客户端还要求你指定用户,此处为 `root`。
```bash
% 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` 数据库将包含三张表:`employees`、`teams` 和 `employees_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](https://dolthub.com/docs/concepts/dolt/commits). Dolt commit 允许你进行时间旅行并查看血缘关系。每当你想恢复到这一时间点或与之进行比较时,就创建一个 Dolt commit。
Dolt 通过类似 Git 的界面暴露版本控制功能。在命令行中,Dolt 命令与对应的 Git 命令一一映射,只是目标对象从文件变成了表。在 SQL 中,Dolt 将版本控制的读操作暴露为[系统表](https://dolthub.com/docs/sql-reference/version-control/dolt-system-tables),将版本控制的写操作暴露为[存储过程](https://dolthub.com/docs/sql-reference/version-control/dolt-sql-procedures).
系统表和存储过程的命名遵循 `dolt_` 模式。因此,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`](https://dev.mysql.com/doc/refman/5.6/en/innodb-autocommit-commit-rollback.html) 运行数据库,因此每条 SQL 语句都会自动生成事务 `COMMIT`。如果你希望系统为每个事务生成 Dolt commit,请使用系统变量 [`@@dolt_transaction_commit`](https://dolthub.com/docs/sql-reference/version-control/dolt-sysvars#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 最多支持十二表 `JOIN`s。再说一次,Dolt 是现代 SQL 关系型数据库,并配有 Git 风格的版本控制。
## 查看 diff
现在,如果你想在提交之前查看工作区里有哪些变更,可以使用 `dolt_status` 和 `dolt_diff_` 系统表。
```
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()`](https://dolthub.com/docs/sql-reference/version-control/dolt-sql-procedures#dolt_revert). 撤销特定提交。即使你意外在错误的数据库上运行了 `drop database`,Dolt 也允许你通过调用 [`dolt_undrop()` stored procedure](https://dolthub.com/docs/sql-reference/version-control/dolt-sql-procedures#dolt_undrop). 来撤销该操作。
## 在 SQL Workbench 中查看数据
讨厌命令行?让我们使用 [Tableplus](https://tableplus.com/) 进行一些修改。Tableplus 是一款免费的 SQL Workbench。请按照其官网的安装说明进行操作。
现在,要连接数据库,你必须选择 MySQL 作为连接类型。然后为连接输入一个名称,将 `getting_started` 作为数据库,将 `root` 作为用户。

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

## 在分支上进行更改
要在分支上进行更改,我使用 `dolt_checkout()` 存储过程。使用 `-b` 选项会创建分支,就像在 Git 中一样。
Tableplus 让我可以在 SQL 选项卡中输入多行 SQL 脚本。我输入了以下 SQL,用于检出分支、更新、插入、删除,最后 Dolt commit 我的更改。
```SQL
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 中的结果。

回到终端后,我看不到在 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_` 和 `dolt_diff_` 来探索 Dolt 中的血缘功能。
`dolt_history_` 会显示该行在每一个 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_` 允许你将历史记录筛选为仅显示目标单元格发生变更的 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 有了初步了解,请前往 [我们的文档](https://dolthub.com/docs/introduction/what-is-dolt)。你也可以在 [我们的博客](https://www.dolthub.com/blog/). 中了解我们一直在做什么。
# 安全策略
[Dolt 当前的安全策略](https://github.com/dolthub/dolt/blob/main/SECURITY.md) 维护在本仓库中。请按照其中的披露说明操作。请勿在本仓库的公开 GitHub Issues 中初次报告安全问题。
# 致谢与许可
Dolt 大量依赖来自
[Noms](https://github.com/attic-labs/noms) 项目的开源代码和理念。我们非常感谢 Noms 团队免费提供这些代码,
没有它们,我们无法如此快速地构建 Dolt。
Dolt 采用 Apache License, Version 2.0 许可。详见
[LICENSE](https://github.com/dolthub/dolt/blob/master/LICENSE)。