Marko Ivankovic выпустил OmniDiff, быстрый diff для git на Rust

Marko Ivankovic опубликовал на GitHub OmniDiff, программу для сравнения файлов, написанную на Rust. Автор описывает её как быструю, надёжную и точную, учитывающую тип содержимого. В README заявлены два главных показателя: инструмент справляется с 99,95% изменений кода из тестового набора, а 98,8% изменений разбираются алгоритмами, специфичными для типа содержимого.
Как это работает. Язык определяется по расширению файла. Для 25 языков используется грамматика tree-sitter, и сравнение идёт по структуре кода. Файлы с неизвестным расширением сравниваются как обычный текст построчно, так что ничего не отклоняется. Для шести форматов (Bazel, Dart, Emacs Lisp, Markdown, Protocol Buffers, SQL) грамматики не подключены, и они тоже сравниваются как текст. Не текстовые файлы распознаются по байтам, а не по имени, и сравниваются по содержимому: архивы, шрифты, PDF, картинки (в том числе анимированные), файлы OpenDocument, скомпилированные каталоги переводов. Открываются только изменившиеся элементы: у шрифта с двумя правками покажут два глифа. Каждое изменение получает оценку заметности для читателя: невидимое (отличаются лишь байты), неразличимое, артефакты сжатия или передискретизации, правка, перерисовка или замена. Любой другой бинарный файл получает однострочное сообщение «Binary file … differs».
Интерфейс и интеграции. Есть полноэкранный терминальный просмотрщик (TUI) с 24-битным цветом, если терминал его объявляет, и с 256 цветами в остальных случаях. Картинки он показывает средствами терминала (протоколы kitty, sixel, iTerm2) или полублоками Unicode. Режим --headless (синоним --batch) печатает diff простым текстом и включается автоматически, если вывод идёт не в терминал, например в less или файл. Режим --mode json печатает diff одним JSON-объектом со схемой в репозитории. По умолчанию показываются 3 строки контекста вокруг изменения (меняется ключом --context N), а перед блоком изменений добавляется ближайшая объемлющая функция, класс или структура. Код возврата: 0 при успехе, 2 при ошибке, а 1 при различиях, только с флагом --exit-code, чтобы системы контроля версий не считали отличие файлов сбоем инструмента.
Инструмент подключается как difftool для git (мастер настройки: omnidiff git configure) и через GIT_EXTERNAL_DIFF для git diff и git log -p; там вывод всегда текстовый, интерактивный просмотрщик открывает только git difftool. Для jj есть отдельный мастер (omnidiff jj configure), при этом необходим режим вызова file-by-file. Расширения: для VS Code и Neovim (omnidiff-vscode, omnidiff.nvim; встроенный diff-просмотр VS Code пока нельзя заменить расширением, нужный API реализован в основной ветке, но не выпущен). Есть и браузерный инструмент ревью codereview, но он версии v0.0.0, и автор советует использовать его на свой риск.
Установка: cargo install --locked omnidiff (нужны компилятор C и rustc 1.92 или новее; первая сборка занимает несколько минут из-за компиляции грамматик и профиля lto = "fat"), готовые бинарники для Linux, macOS (Intel и Apple Silicon) и Windows в релизах GitHub, brew, подписанный apt-репозиторий с пакетами .deb для amd64 и arm64, nix run, рецепты для Arch и Gentoo.
Скорость. Цели автора: медианный diff не дольше 100 мс и 99-й процентиль не дольше 1000 мс; README утверждает, что обе выполнены. На 2302 тестовых примерах (измерение от 31 октября 2026 года на ноутбуке с Intel Core i7-1370P и 32 ГБ ОЗУ): медиана 4,2 мс, p90 35,1 мс, p99 177 мс, самый медленный случай 482 мс. 100 мс, это 97,6-й процентиль: дольше идут 55 примеров, но ни один не дольше секунды. Серверу с Intel Xeon E3-1275 v5 на тот же пример нужно примерно в 2,5 раза больше времени. Для прочего содержимого картина хуже: архивы не укладываются в цель по 99-му процентилю (в самых тяжёлых тысячи изменённых элементов), PDF обе цели выполняют, но лишь 57% из них считаются быстрее 100 мс, поскольку отрисовываются все изменённые страницы.
Как получена цифра 99,95%. Тестовый набор, история коммитов примерно 7500 открытых git-репозиториев (список взят из дистрибутива Gentoo Linux). Взяты все изменённые файлы с кодом из последних 50 коммитов каждого репозитория: 442 530 читаемых пар «до/после» на 25 языках, сравнение без ограничения размера, с лимитом 120 секунд и 6 ГБ памяти на процесс. Успешно завершились 442 322 пары (99,95%); 96 пар вышли за лимит времени и 112 за лимит памяти. Цель автора, обработать 100% всех коммитов.
Лицензия. Программа распространяется по GNU AGPL версии 3, авторские права принадлежат Marko Ivankovic (2026). Для организаций предлагается коммерческая лицензия по ежемесячной подписке через GitHub Sponsors: она покрывает внутреннее использование без обязательства раскрывать исходный код по AGPL.
Ключевые факты
- OmniDiff, открытый diff-инструмент на Rust: TUI-просмотрщик, безголовый режим (--headless), вывод в JSON, интеграция с git (difftool и GIT_EXTERNAL_DIFF) и jj.
- Для 25 языков код сравнивается по структуре через tree-sitter; архивы, шрифты, PDF, картинки и OpenDocument сравниваются по содержимому, неизвестные расширения, построчно как текст.
- Скорость по данным README: на 2302 примерах на ноутбуке автора (Core i7-1370P) медиана 4,2 мс, p99 177 мс, самый медленный случай 482 мс; на сервере с Xeon E3-1275 v5 примерно в 2,5 раза медленнее.
- Цифра 99,95%, доля пар, завершившихся в лимите 120 с и 6 ГБ: 442 322 из 442 530 пар из примерно 7500 репозиториев; 96 пар вышли за лимит времени, 112, за лимит памяти.
- Лицензия AGPL-3.0; коммерческая лицензия без обязательств AGPL, по ежемесячной подписке через GitHub Sponsors.
Почему это важно
Сравнение файлов, ежедневная операция в разработке, а привычный построчный diff плохо различает структуру кода и вовсе не умеет показывать содержательные изменения в бинарных форматах. OmniDiff пытается закрыть оба пробела: разбирает код 25 языков по грамматикам tree-sitter и отдельно описывает изменения в архивах, шрифтах, PDF и картинках. Заявленная скорость (медиана 4,2 мс на ноутбуке автора) подаётся как достаточная, чтобы инструмент не мешал в повседневной работе, но эти цифры взяты из README и измерены на одной машине.
Кому это важно
Прежде всего разработчикам, которые много читают дифы в терминале, используют git или jj и хотят видеть изменения в контексте функций и классов. Также тем, кто сравнивает не только текст: например, версии шрифтов, документов OpenDocument или картинок. Команды, которым нужен вывод для скриптов и CI, могут воспользоваться безголовым режимом и JSON-выводом. Организациям стоит заранее учесть условия лицензии AGPL.
Как это применить
Установка: cargo install --locked omnidiff (нужны компилятор C и rustc 1.92 или новее), либо готовые бинарники Linux, macOS и Windows, либо brew install ivankovic/omnidiff/omnidiff, либо пакет .deb из подписанного apt-репозитория, либо nix run github:ivankovic/omnidiff. Для git запустите omnidiff git configure (или настройте difftool вручную и выберите git difftool --tool=omnidiff); для jj, omnidiff jj configure, при этом нужен режим file-by-file. Просто посмотреть два файла: omnidiff BEFORE AFTER. Для скриптов, omnidiff --headless BEFORE AFTER, а флаг --exit-code даст код 1 при различиях. Лицензия: AGPL-3.0; организациям, которым не подходят её требования об открытии исходного кода, автор предлагает коммерческую лицензию по ежемесячной подписке через GitHub Sponsors. Условия, в файле LICENSE-COMMERCIAL.
Можно ли доверять
Все цифры о скорости и надёжности, собственные измерения автора из README, независимых проверок в доступном тексте нет. Скорость замерена на одном ноутбуке (Intel Core i7-1370P), на сервере с Xeon E3-1275 v5 тот же пример занимает примерно в 2,5 раза больше времени. Показатель 99,95% описывает долю пар, успешно завершивших работу в пределах лимитов времени и памяти, а не правильность результата: за точность отвечает отдельный раздел «Accurate», которого в доступном тексте не видно. Само README сообщает, что у PDF меньше десяти оценённых тестовых случаев. Сравнения по времени с другими инструментами, такими как git diff, в доступном тексте нет. Текст источника обрывается на описании сбоев по памяти, поэтому о последующих разделах судить нельзя.
Риски и подводные камни
Лицензия AGPL накладывает обязательства по раскрытию исходного кода; для внутреннего использования в организации без них нужна платная коммерческая лицензия. Сборка из исходников требует компилятора C и занимает несколько минут. Шесть форматов (Bazel, Dart, Emacs Lisp, Markdown, Protocol Buffers, SQL) сравниваются просто как текст. Архивы не укладываются в цель по p99, а PDF в 43% случаев занимают 100 мс и больше. Расширение для VS Code пока не может заменить встроенный просмотр diff, а браузерный codereview имеет версию v0.0.0 и используется на свой риск. В git diff и git log -p интерактивный режим не откроется, там вывод всегда текстовый; для интерактивного просмотра нужен git difftool, а по SSH, терминал с выделенным псевдотерминалом (ssh -t).
«Цель OmniDiff, обработать 100% всех коммитов.»
— README проекта OmniDiff