画像・バイナリ・URL・クリップボード・公開中のサイト・SSH 越しのディレクトリ。どれも同じコマンドで、同じ 2 つを答える ── 違うか、どこが。ウィンドウは開かない。
brew install 1 回・依存なし
MIT ライセンス — 無料
$ mrdiff before.png after.png Images differ — 12,481 of 390,000 pixels (3.2%) First difference at (412, 88) largest per-channel gap: 41 — --tolerance=41 would call these the same $ mrdiff firmware-v1.bin firmware-v2.bin Binary files differ — 47 regions, first at 0x1A3F 158 of 2,000,000 bytes differ $ mrdiff --ssh ./site deploy@host:/var/www changed config/app.yml only local (not deployed) pages/new.html only on remote (left over?) backups/customers.sql 1 changed, 1 only local, 1 only on remote
画像も、バイナリも、サーバも、同じ形の答え。いま開いているターミナルの中に。
違うか、どこが。
MrDiff が答えるのはこの 2 つで、そう決めてある。差分を見せることはしない。その代わり、テキストでも画像でもバイナリでも、公開中のサイトでも 10 GB のログでも、同じ問いに同じ形で答える。ファイルの種類ごとに道具を覚えなくていい。
どの比較を走らせるかは、拡張子ではなく中身で決める。.bin と名付けられた PNG も画像として比べる。
違うか、何画素が、最初はどこか。画素を数えるので、1 画素の違いが「0.0%」に丸まることはない。--tolerance=N で小さな値のずれを同じとみなせる。緩めたときは出力にそう書く — 何も付かない「同じ」は、必ずバイト単位で同じという意味。
$ mrdiff --tolerance=2 a.png b.jpg Images differ — 1,560 of 390,000 pixels (0.4%) compared with ±2 per channel largest per-channel gap: 5 — --tolerance=5 would call these the same
違う箇所がいくつあり、最初はどのオフセットか(16 進)。隣り合うバイトは 1 箇所と数える。長さが違えば共通部分だけを比べ、余りは余りとして言う — 1 バイトの挿入が「以降ぜんぶ違う」にはならない。
$ mrdiff v1.bin v2.bin Binary files differ — 47 regions, first at 0x6BDF 158 of 2,000,000 bytes differ
行の差分に、文字単位のハイライト。動いた 1 文字に印が付く — 行ごと赤く塗るだけでは足りない。行番号は左右 2 列。消えた 7 行目と増えた 7 行目は同じ行ではない。
mrdiff https://a https://b は両方を取ってきて、サーバが返したものを比べる。--clipboard は、いまコピーしたもの — 文字が無ければスクリーンショット — をファイルや URL と比べる。何も保存せずに「さっきのと同じ?」が聞ける。
--site はフォルダの git 管理下のファイルを 1 つずつサイトから取ってきて、合わないものを言う: 違う、またはサイトに無い。「置いてあるべきファイル」を決めるのは git ls-files なので、ビルドの中間物や .DS_Store は数えない。「これ、デプロイし忘れてない?」が CI のチェックになる。
$ mrdiff --site https://example.com ./site changed index.html not on site pricing.html 1 changed, 1 not deployed, 0 could not be checked note: files on the site that are not in git cannot be found this way (HTTP has no directory listing)
host:/path はファイルとして使える。--ssh はツリー全体を両方向で見る。だから、デプロイ確認がふつう出せない 3 つ目が出る: サーバにあってリポジトリに無いファイル — 古い書き出し、忘れたバックアップ。認証は手元の ssh のもの: 鍵、~/.ssh/config、agent。パスワードは聞かない。
--exit-code違えば 1 で終わる。スクリーンショットの回帰、ファームウェアのビルド比較、「生成物は変わったか」 — 差分を見る必要は無く、あるかどうかだけ知りたい場面のため。
--json機械向け。訳さない — 出力を grep するスクリプトは、使う人の言語が何でも壊れない。
2 つが同じだと言うには、両方を最後まで読むしかない — ハッシュでもそれは避けられない。避けるのは、既に一致しているブロックの中の 1 バイトずつの比較。5 バイトだけ違う 1 GB は、同じ 1 GB とほぼ同じ時間で済む(コールドで 4.3 秒、キャッシュから 0.1 秒、M4 Max)。
アカウントも、テレメトリも、サーバも無い。URL はキャッシュを使わず取るので、古い写しと比べることがない。リクエストは mrdiff と名乗る。
どれも道具が自分で毎回そう言う。使う人が後で気づく形にはしない。
答えるのは「違うか」と「どこが」。2 枚の画像や 2 つのファームウェアがどう違うかを見るのは別の道具の仕事で、MrDiff はそのふりをしない。
JavaScript は動かさないし描画もしないので、ブラウザで見える画面と答えが違うことがある。そこをごまかすと、無い違いを「違う」と言う道具になる。
行の文字列を比べる。整形を変えただけでも違いに数える。**強調** を外した、キーの順番を変えた、といった「意味は同じ」を同じと言うのは、この版の仕事の外。
--site は、git に無いファイルを見られないHTTP にはディレクトリ一覧が無い。サーバに置き忘れた customers.xlsx はここからは見えず、「サイトはきれい」と読ませないために毎回そう書く。SSH ならリモート側を列挙できるので、そちらでは出る。
brew install 1 回。ほかに設定するものは無い。
$ brew install mr-tabata/tap/mrdiff # あとは $ mrdiff a.png b.png $ mrdiff a.bin b.bin $ mrdiff https://example.com/a https://example.com/b $ mrdiff --clipboard notes.md $ mrdiff --site https://example.com ./site $ mrdiff local.conf host:/etc/app.conf $ mrdiff --ssh ./site host:/var/www $ mrdiff --exit-code a.png b.png # 違えば 1 で終わる $ mrdiff --json a.bin b.bin # 機械向け
macOS 専用。Swift 製で、画像の読み込みに OS の ImageIO を使うため。
出力は既定で英語。MRDIFF_LANG=ja で人向けの行だけ日本語になる。JSON と終了コードは変わらない。