CLI 参考手册
merql 自带一个 CLI,可直接从终端捕获快照、计算差异并运行合并。Composer 会将其安装为 vendor/bin/merql;在 merql 仓库的检出目录中,它是 bin/merql。
由于 merql 0.4.1,vendor/bin/merql 可在安装依赖后正常运行。早期版本只会在软件包自己的 vendor/ 目录中查找 Composer 自动加载器,因此 merql 作为依赖安装时会运行失败。
快速开始
# Capture a baseline from your database.
export MERQL_DB_DSN="sqlite:/path/to/db.sqlite"
vendor/bin/merql snapshot base
# Make some changes, then capture again.
vendor/bin/merql snapshot current
# See what changed.
vendor/bin/merql diff base current
三方合并需要从两个相对于基准发生分歧的数据库中捕获 ours 和 theirs。为每个快照将 MERQL_DB_DSN 指向正确的数据库:
# Base: live before the sandbox was copied from it.
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
# ... copy live.sqlite to sandbox.sqlite, then both databases change ...
MERQL_DB_DSN="sqlite:/data/sandbox.sqlite" vendor/bin/merql snapshot ours
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot theirs
# Three-way merge with dry-run preview.
vendor/bin/merql merge base ours theirs --dry-run
依次从同一个数据库捕获全部三个快照,不能用于合并:theirs 会包含 ours 已做的更改,因此 ours 插入的每一行都会被报告为 insert_insert 冲突。
环境变量
CLI 从环境变量读取数据库连接详细信息。你可以使用 PDO DSN 字符串或单独的 MySQL 参数进行连接。
基于 DSN 的连接
对于基于 PDO 的连接,请使用 MERQL_DB_DSN。这是针对 SQLite 和非标准配置的推荐方法。DSN 必须指向 MySQL 或 SQLite 数据库:CLI 无法为其他引擎注册驱动程序。
| 变量 | 说明 | 示例 |
|---|---|---|
MERQL_DB_DSN |
完整 PDO DSN 字符串 | sqlite:/path/to/db.sqlite |
MERQL_DB_USER |
用户名(使用 DSN 时可选) | root |
MERQL_DB_PASS |
密码(使用 DSN 时可选) | secret |
# SQLite file.
export MERQL_DB_DSN="sqlite:/var/data/myapp.sqlite"
# MySQL via DSN.
export MERQL_DB_DSN="mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4"
export MERQL_DB_USER="root"
export MERQL_DB_PASS="secret"
使用基于文件的 SQLite 数据库。每个 CLI 命令都在独立进程中运行,因此 sqlite::memory: 总会打开一个新的空数据库,其快照中不包含任何表。
MySQL 简写
未设置 MERQL_DB_DSN 时,CLI 会改用特定于 MySQL 的变量。
| 变量 | 默认值 | 说明 |
|---|---|---|
MERQL_DB_NAME |
(必填) | 数据库名称 |
MERQL_DB_HOST |
127.0.0.1 |
MySQL 主机 |
MERQL_DB_PORT |
3306 |
MySQL 端口 |
MERQL_DB_USER |
root |
MySQL 用户名 |
MERQL_DB_PASS |
(空) | MySQL 密码 |
MERQL_DB_ADAPTER |
pdo |
设为 mysqli 以使用 mysqli 适配器 |
export MERQL_DB_NAME="wordpress"
export MERQL_DB_HOST="127.0.0.1"
export MERQL_DB_PORT="3306"
export MERQL_DB_USER="root"
export MERQL_DB_PASS="password"
命令
merql snapshot <name>
捕获环境变量所指定数据库的当前状态,并将其保存为命名快照。这是唯一会连接数据库的命令。
vendor/bin/merql snapshot baseline
输出:
Snapshot 'baseline' saved
Tables: posts, comments, users, settings
快照默认以 JSON 文件的形式持久化到工作目录下的 .merql/snapshots/ 中(参见 快照存储)。名称只能包含字母数字字符、连字符和下划线。
典型工作流程:进行更改前捕获一个快照,然后在更改后再捕获一个。两个快照构成计算差异或执行合并的基础。
merql diff <base> <current>
比较两个命名快照并显示差异摘要。
vendor/bin/merql diff baseline current
输出:
Changeset: baseline -> current
Inserts: 3
Updates: 7
Deletes: 1
两个快照都必须已存在(此前通过 merql snapshot 捕获)。差异计算基于保存的快照文件,无需连接数据库。
merql merge <base> <ours> <theirs>
对三个命名快照执行三方合并。
vendor/bin/merql merge base ours theirs
输出:
Merge: base + ours + theirs
Operations: 12
Conflicts: 0
Clean: yes
三个快照都必须已存在。合并基于保存的快照文件,无需连接数据库,也不会写入数据库:CLI 没有 apply 命令。使用 PHP API 应用合并结果。
CLI 在列级别进行合并。它不会对 TEXT 或 JSON 列执行单元格级合并,因此同一列中的两处不同编辑在此始终会产生冲突(#7)。如需单元格级合并,请在 PHP 中将 ThreeWayMerge 与 CellMergeConfig 配合使用。
--dry-run
添加 --dry-run 标志可预览合并将生成的 SQL 语句,而不执行任何操作。这些语句描述如何将基准状态转换为合并结果,因此包含双方的更改。
vendor/bin/merql merge base ours theirs --dry-run
输出:
Merge: base + ours + theirs
Operations: 3
Conflicts: 0
Clean: yes
Dry run SQL:
INSERT INTO `posts` (`id`, `title`, `status`) VALUES ('10', 'New Post', 'draft');
UPDATE `posts` SET `title` = 'Updated Title' WHERE `id` = '5';
DELETE FROM `comments` WHERE `id` = '3';
开发命令
merql 仓库的检出目录中,bin/ 下还有供 oracle 驱动测试套件使用的脚本。这些脚本不属于 Composer 软件包,因此仅安装依赖时只有 vendor/bin/merql。在仓库根目录中 composer install 后运行这些脚本。
| 命令 | 说明 |
|---|---|
./bin/oracle <name> |
计算场景的预期合并结果 |
./bin/actual <name> |
在场景上运行 merql 并捕获输出 |
./bin/compare <name> |
对比 oracle 与实际输出 |
./bin/test-scenario <name> |
完整流程:设置、oracle、实际结果、比较 |
./bin/test-regression |
运行所有场景 |
./bin/test-regression --category clean |
运行一个类别:clean、conflict、identity、types、scale 或 edge |
./bin/test-regression --fast |
仅显示通过/失败,不生成报告 |
./bin/verify-compliance |
完整合规报告 |
./bin/verify-all |
PHPStan + 代码风格 + PHPUnit + oracle 回归测试 |
bin/test-regression 也接受 --jobs,但目前会忽略该值并依次运行场景(#5)。遇到未知的 --category 时会打印 No scenarios found 并成功退出。
场景布局请参阅 测试策略。
退出状态
merql snapshot、diff 和 merge 缺少参数时会以状态码 1 退出;snapshot 在未配置连接时也会如此。缺少快照会导致命令因未捕获的 SnapshotException 而结束,并返回非零状态码。遇到未知命令时会打印 Unknown command,但目前会以状态码 0 退出(#3)。
快照存储
快照存储在相对于工作目录的 .merql/snapshots/ 中。每个快照都是一个名为 <name>.json 的独立 JSON 文件。所有命令都要从同一目录运行,才能找到彼此的快照。
CLI 没有用于指定其他位置的选项或环境变量(#8)。如需使用其他位置,请在运行前切换到不同的工作目录。在 PHP 中,捕获或加载快照前先设置目录:
use Merql\Snapshot\SnapshotStore;
SnapshotStore::setDirectory('/var/data/merql-snapshots');
快照文件可移植。你可以在不同计算机之间复制它们,将它们提交到版本控制中,或分享以便协作调试。由 CLI 捕获的快照可以在 PHP 中使用 SnapshotStore::load() 加载,反过来也可以,只要两者使用相同目录即可。