跳转到正文

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 中,捕获或加载快照前先设置目录:

PHP
use Merql\Snapshot\SnapshotStore;

SnapshotStore::setDirectory('/var/data/merql-snapshots');

快照文件可移植。你可以在不同计算机之间复制它们,将它们提交到版本控制中,或分享以便协作调试。由 CLI 捕获的快照可以在 PHP 中使用 SnapshotStore::load() 加载,反过来也可以,只要两者使用相同目录即可。