
Вводишь поисковый запрос через grep или ripgrep в большом монорепозитории или проекте на сотни тысяч файлов, и терминал подвисает на 10–30 секунд?
В Microsoft тоже столкнулись с этой же проблемой и создали tgrep — утилиту на Rust с триграммной индексацией и клиент-серверной архитектурой. Сейчас tgrep уже интегрирован в GitHub Copilot CLI и доступен в open source под свободной лицензией MIT.
В этой статье разберем, как он устроен, как установить его на macOS и как внедрить в повседневную работу.
В чем магия tgrep и почему он быстрее ripgrep?#
Привычные утилиты (grep, ripgrep, ag) работают линейно: на каждый поисковый запрос они заново обходят дерево файлов и читают их содержимое с диска (сложность $O(\text{объем байт})$). Даже при параллельном чтении и быстром SSD на миллионах строк кода это занимает ощутимое время.
tgrep использует иной подход:
- Триграммный индекс: во время предварительной индексации файл разбивается на 3-символьные последовательности (триграммы). Из них строится компактная инвертированная таблица поиска.
- Мгновенная фильтрация: при поиске регулярное выражение парсится на литеральные фрагменты и триграммы.
tgrepмгновенно исключает подавляющую часть файлов, где совпадения гарантированно быть не может, и запускает полный regex-поиск только по оставшимся кандидатам. - Клиент-серверный режим: демон
tgrep serveдержит индекс в памяти и слушает изменения файловой системы через нативный механизм macOS — FSEvents. Любые правки мгновенно попадают в in-memory оверлей (LiveIndex). Поисковый клиентtgrepсвязывается с сервером по локальному TCP (JSON-RPC) и получает результат за миллисекунды.
Бенчмарки на macOS (Apple Silicon arm64)#
В замерах разработчиков Microsoft на реальных кодовых базах:
| Репозиторий | Файлов | ripgrep | tgrep | Ускорение |
|---|---|---|---|---|
| gecko-dev (Firefox) | 388 000 | 33.4 с | 0.64 с | ~52x |
| chromium | 504 000 | 41.8 с | 2.64 с | ~16x |
| linux kernel | 96 000 | 5.4 с | 0.26 с | ~21x |
Установка на macOS#
Способ 1: Homebrew (рекомендуется)#
tgrep уже добавлен в официальный репозиторий Homebrew core, поэтому ставится одной командой:
brew install tgrepПроверяем установку:
tgrep --versionСпособ 2: Готовые бинарники с GitHub Releases#
Если вы не пользуетесь Homebrew или хотите скачать релиз напрямую через GitHub CLI:
Для Apple Silicon (M1/M2/M3/M4):
gh release download --repo microsoft/tgrep -p '*aarch64-apple-darwin*' -D /tmp/tgrep-dl
sudo tar xzf /tmp/tgrep-dl/tgrep-*-aarch64-apple-darwin.tar.gz -C /usr/local/binДля процессоров Intel:
gh release download --repo microsoft/tgrep -p '*x86_64-apple-darwin*' -D /tmp/tgrep-dl
sudo tar xzf /tmp/tgrep-dl/tgrep-*-x86_64-apple-darwin.tar.gz -C /usr/local/binРабочий процесс#
1. Построение индекса (tgrep index)#
Перейдите в корень вашего проекта и постройте индекс:
cd ~/my-big-project
tgrep index .Индекс сохраняется в локальную директорию .tgrep/.
Обязательно добавьте .tgrep в ваш .gitignore или глобальный ~/.gitignore, чтобы не коммитить файлы индекса в репозиторий:
echo ".tgrep/" >> .gitignore2. Запуск фонового сервера (tgrep serve)#
Чтобы не перестраивать индекс вручную после каждой правки кода, запустите сервер наблюдения:
tgrep serve . &Сервер использует Apple FSEvents, потребляет минимум ресурсов в фоне и поддерживает актуальность индекса при любых изменениях файлов.
Проверить состояние сервера можно командой:
tgrep status .Вывод покажет PID процесса, открытый TCP-порт, количество проиндексированных файлов, число триграмм и статус наблюдателя (Watcher: active).
3. Поиск по коду#
Теперь можно выполнять поисковые запросы. Клиент автоматически обнаружит запущенный сервер и выдаст ответ почти мгновенно:
tgrep "handle_request" .Полезные флаги и примеры (совместимость с ripgrep)#
Интерфейс командной строки tgrep намеренно повторяет синтаксис ripgrep (rg), поэтому переучиваться не придется:
Поиск точной подстроки без регулярных выражений (-F)#
tgrep -F "Map<String, List<User>>" .Поиск слова целиком (-w) и без учета регистра (-i или -S)#
tgrep -w "config" . -i
# -S / --smart-case: регистронезависимый поиск, если паттерн в нижнем регистре
tgrep -S "myfunction" .Ограничение типами файлов (-t) или глоб-паттернами (-g)#
# Только Rust файлы
tgrep "struct Config" . -t rust
# Только TypeScript и JavaScript
tgrep "export const" . -g "*.{ts,tsx,js}"Список всех поддерживаемых типов файлов можно посмотреть через:
tgrep --type-listВывод контекста вокруг совпадения#
tgrep -C 3 "panic\!" . # 3 строки до и после
tgrep -A 2 -B 1 "throw new" . # 2 строки после, 1 строка доТолько имена файлов (-l) или подсчет количества (-c)#
tgrep -l "TODO" .
tgrep -c "deprecated" .Вывод в формате JSON или Vim#
# JSON-стрим (полностью совместим со схемой ripgrep)
tgrep --json "fn main" .
# Формат file:line:col:text для редакторов
tgrep --vimgrep "unwrap()" .Быстрый листинг проиндексированных файлов#
# Мгновенно показывает список всех файлов без сканирования диска
tgrep --files .
tgrep --files -t python .Поиск в обход индекса (--no-index)#
Если вам разово требуется классическое сканирование диска в обход сервера и индекса:
tgrep "query" . --no-indexВажные нюансы#
- Репозитории без
.git: если вы индексируете обычную папку без инициализированного git-репозитория, добавьте флаг--no-require-git, чтобыtgrepучитывал имеющийся.gitignore:tgrep index . --no-require-git tgrep serve . --no-require-git - Соблюдайте одинаковые флаги: флаги исключений (
--exclude,--max-filesize,--no-ignore) должны быть одинаковыми уtgrep indexиtgrep serve. - Лимит размера файлов: по умолчанию
tgrepпропускает файлы больше 64 МБ, чтобы тяжелые сгенерированные артефакты и бандлы не раздували индекс. Если нужно снять лимит, используйте--no-max-filesize. - AI-агенты (Cursor, Claude Code, Opencode):
tgrepизначально создавался как инструмент для агентов. За счет субсекундных ответов агент не тратит время на ожиданиеgrepпо огромным репозиториям.
Итог#
Для небольших проектов старый добрый ripgrep остается непревзойденным классическим вариантом.
Но если вы работаете с крупными проектами, монорепозиториями на десятки тысяч файлов или автоматизируете работу AI-агентов, связка tgrep index + tgrep serve превращает долгий поиск в мгновенное действие.


