Прощай, `filter-branch`: Как `git-filter-repo` навёл порядок в истории Git

01 Jan, 2026

Когда в последний раз вам приходилось переписывать историю Git? Удалить коммит с большим файлом, вынести часть монорепозитория в отдельный проект, или просто навести порядок после долгих экспериментов? Если ваш опыт связан с git filter-branch, то, скорее всего, вы помните эту боль: медлительность, неочевидные ошибки и риск испортить всё, если хоть немного отвлечься. А BFG Repo Cleaner, хоть и был неплох, часто оказывался слишком ограниченным для сложных задач.

Знакомая ситуация, не правда ли? К счастью, сообщество Git осознало эти проблемы и теперь официально рекомендует новый, гораздо более мощный и безопасный инструмент для работы с историей репозиториев: git-filter-repo.

Что это за git-filter-repo и кому он нужен?

Что же это за зверь такой – git-filter-repo? Представьте себе швейцарский армейский нож для истории Git. Это универсальный инструмент, написанный на Python, который пришёл на смену устаревшим и проблемным решениям. Его главная цель – дать разработчикам возможность легко и безопасно переписывать историю репозитория, будь то удаление конфиденциальных данных, изменение структуры проекта или разделение монорепозитория.

Кому это нужно? Да практически каждому, кто хоть раз сталкивался с необходимостью "почистить" или изменить историю. От джуниоров, случайно закоммитивших файл с паролями, до опытных тимлидов, которым нужно реструктурировать большой проект. git-filter-repo создан, чтобы сделать эти задачи не просто возможными, но и приятными.

Ключевые возможности: За что его стоит полюбить?

Давайте посмотрим, что делает git-filter-repo таким особенным и почему он быстро завоевал сердца разработчиков.

Скорость, которая поражает

Одной из самых больших проблем git filter-branch была его удручающая медлительность. На больших репозиториях выполнение операции могло занимать часы или даже дни. git-filter-repo решает эту проблему кардинально. Он работает в разы, а то и на порядки быстрее своих предшественников. Это не просто улучшение, это – совершенно новый уровень комфорта при работе с большими объёмами данных.

Безопасность превыше всего

Переписывание истории – это всегда риск. filter-branch был известен своими "подводными камнями", которые могли незаметно повредить репозиторий. git-filter-repo разработан с учётом этих проблем. Он по умолчанию требует работать в свежем клоне репозитория, что значительно снижает риск случайной порчи данных в основном проекте. А если вы всё же забудете об этом, инструмент вежливо напомнит и не даст вам наломать дров. Это как иметь страховку, когда делаешь что-то рискованное.

Невероятная гибкость и мощь

В отличие от BFG Repo Cleaner, который был ограничен несколькими сценариями, git-filter-repo предлагает куда больше возможностей. Он позволяет:

  • Фильтровать по путям: Легко извлекать историю отдельных директорий или файлов, создавая новые репозитории.
  • Переименовывать: Менять названия файлов, директорий и даже префиксы тегов.
  • Работать с тегами: Переименовывать теги, избегая конфликтов при слиянии.
  • Автоматически очищать: После операции он сам удаляет старые объекты и перепаковывает репозиторий, избавляя вас от рутины с git gc.
  • Расширяемость: Если вам нужны специфические операции, git-filter-repo можно использовать как библиотеку для создания собственных скриптов фильтрации на Python, что открывает безграничные возможности.

Умная обработка истории

Проект не просто удаляет файлы, но и интеллектуально работает с историей:

  • Удаление пустых коммитов: Коммиты, которые становятся пустыми после фильтрации, автоматически удаляются, сохраняя при этом коммиты, изначально созданные пустыми (например, для версионирования).
  • Перезапись ссылок на SHA: Если в сообщениях коммитов есть ссылки на старые SHA-хеши других коммитов, git-filter-repo может их автоматически обновить, чтобы они указывали на новые, переписанные коммиты. Это мелочь, но как же она важна для сохранения целостности истории!

Технические детали: Простота и эффективность

Под капотом git-filter-repo – это один-единственный Python-скрипт. Это делает его установку невероятно простой: достаточно поместить файл git-filter-repo в ваш $PATH. Из зависимостей — только git версии 2.36.0 или выше и python3 версии 3.6 или выше. Никаких сложных конфигураций, никаких зависимостей, которые тянут за собой пол-интернета. Просто и надёжно.

Кстати, интересно, что разработка git-filter-repo не только дала нам отличный инструмент, но и подтолкнула к улучшению самого git fast-export и git fast-import в ядре Git. Многие изменения и исправления, которые мы видим в последних версиях Git, были вдохновлены или напрямую связаны с потребностями git-filter-repo. Это отличный пример того, как один проект может двигать вперёд всю экосистему.

Практическое применение: Где git-filter-repo незаменим?

Давайте представим несколько сценариев, где git-filter-repo станет вашим лучшим другом:

Разделение монорепозитория

Представьте, что у вас есть огромный монорепозиторий, и вы решили выделить из него отдельный микросервис или библиотеку. С git-filter-repo это делается одной командой. Вы просто указываете путь к нужной директории, и инструмент извлекает всю её историю в новый, чистый репозиторий, при этом переименовывая файлы и теги по вашему желанию.

Удаление конфиденциальных данных или больших файлов

Случайно закоммитили файл с API-ключами или гигантский бинарник, который раздувает репозиторий? git-filter-repo позволяет легко удалить такие файлы из всей истории, не оставляя следов. Это критически важно для безопасности и оптимизации размера репозитория.

Рефакторинг структуры проекта

Переехали с одной структуры каталогов на другую? Например, всё лежало в src/, а теперь должно быть в my-module/src/? git-filter-repo справится с этим, переписав все пути в истории, как будто они всегда были такими. Это гораздо чище, чем просто переносить файлы в последнем коммите.

Пример использования: Сравним с конкурентами

Чтобы не быть голословным, давайте рассмотрим пример из README проекта. Нам нужно извлечь историю директории src/, переместить все её файлы в поддиректорию my-module/, и переименовать все теги, добавив префикс my-module-. Посмотрим, как это решается разными инструментами:

git-filter-repo: Элегантно и просто

С git-filter-repo это решается одной, интуитивно понятной командой:

git filter-repo --path src/ --to-subdirectory-filter my-module --tag-rename '':'my-module-'

Здесь мы указываем, что хотим оставить только путь src/, переместить всё содержимое в my-module и добавить префикс my-module- ко всем тегам. Просто, читаемо, эффективно.

BFG Repo Cleaner: Не справляется

Для BFG Repo Cleaner эта задача оказывается не по зубам. Он не предназначен для такого комплексного переписывания истории.

git filter-branch: Много боли и команд

А вот как бы выглядело решение с git filter-branch (один из вариантов, и то с оговорками):

git filter-branch \
    --tree-filter 'mkdir -p my-module && \
                   git ls-files \
                       | grep -v ^src/ \
                       | xargs git rm -f -q && \
                   ls -d * \
                       | grep -v my-module \
                       | xargs -I files mv files my-module/' \
        --tag-name-filter 'echo "my-module-$(cat)"' \
	--prune-empty -- --all
git clone file://$(pwd) newcopy
cd newcopy
git for-each-ref --format="delete %(refname)" refs/tags/ \
    | grep -v refs/tags/my-module- \
    | git update-ref --stdin
git gc --prune=now

И это ещё не всё! Этот пример с filter-branch имеет кучу подводных камней: он медленный, может не работать на разных ОС из-за особенностей grep, xargs, sed, не обновляет SHA-хеши в сообщениях коммитов и требует дополнительных ручных шагов для очистки репозитория. Разница, как говорится, налицо.

Выводы: Стоит ли попробовать?

Итак, если вы хоть раз сталкивались с необходимостью серьёзно поработать над историей своего Git-репозитория, забудьте о мучениях с git filter-branch. git-filter-repo – это современный, быстрый, безопасный и невероятно гибкий инструмент, который не только упрощает сложные задачи, но и делает их выполнимыми. Его официальная рекомендация от самого проекта Git говорит сама за себя.

Попробуйте git-filter-repo в своём следующем проекте, где нужна глубокая очистка или реструктуризация истории. Уверен, вы будете приятно удивлены его мощью и простотой. Ваша история Git заслуживает быть чистой и понятной, а git-filter-repo поможет вам в этом!