Удаление конфиденциальных данных из истории Git: от теории к практике

Привет, Хабр!

Эта статья — мой первый опыт, и я буду рад конструктивной критике. В ней я разберу на реальном примере, как полностью удалить файлы или папки из истории коммитов Git. Это может понадобиться, если вы случайно закоммитили чувствительную информацию (ключи, пароли, конфиги).

Важное предупреждение: Переписывание истории — опасная операция. Её нельзя применять к публичным веткам, с которыми работают другие люди. Это вызовет рассинхронизацию их репозиториев. Всегда сначала меняйте пароли/ключи, если есть возможность! Переписывать историю стоит только если вы точно знаете, что делаете, и работаете в одиночку или договорились с командой.

Инструмент: git filter-repo

Раньше для таких задач часто использовали git filter-branch или BFG, но сейчас сообщество рекомендует более современный и безопасный инструмент — git filter-repo. Его нужно установить отдельно. Всю документацию и способы установки можно найти на официальной странице проекта.

Постановка задачи

Создадим учебный сценарий: мы уже несколько раз закоммитили файлы, а потом осознали, что папка 0.1/ не должна была попасть в репозиторий. Просто добавить её в .gitignore и удалить недостаточно — она останется в истории предыдущих коммитов. Наша цель — стереть её оттуда полностью.

Практическая часть: шаг за шагом

1. Подготовка и осознание проблемы

Сначала мы создали файлы и папки, прокоммитили их, а затем добавили 0.1/ в .gitignore. Однако, как видно на скриншоте, простое добавление в .gitignore не удаляет файл из индекса Git. Он продолжает отслеживаться.

Команда для удаления файла из индекса (staging area), но сохранения его на диске:

git rm -r --cached "0.1"

После этого папка 0.1 перестаёт отслеживаться, и последующие коммиты её не включают. Но она навсегда остаётся в истории прошлых коммитов.

2. Переписывание истории с помощью git filter-repo

Вот команда, которая полностью вычищает папку 0.1 из всей истории Git:

git filter-repo --path "0.1" --invert-paths --force
  • --path "0.1" — указывает, с каким путём работать.

  • --invert-paths — инвертирует условие: удалить все коммиты, затрагивающие этот путь, а не оставить их.

  • --force — принудительный запуск, так как filter-repo отказывается работать в обычном режиме с существующего клона. (По сути, он создаёт новый репозиторий из старого).

Результат: После выполнения команды история переписывается. Все коммиты, в которых фигурировала папка 0.1, исчезают или изменяются (их хэши меняются!). При этом сама папка 0.1 остаётся у вас на диске как неотслеживаемый файл, что и требовалось.

Выводы и полезные ссылки

  • git filter-repo — мощный и рекомендуемый инструмент для очистки истории.

  • Переписывание истории — это --force-пуш и потенциальные проблемы для команды. Всегда предупреждайте коллег!

  • Если скомпрометированы пароли или ключи — лучше сразу поменять их, а не полагаться на удаление из Git.

Дополнительные материалы для изучения:

  1. Официальная документация git filter-repo — очень подробная и полезная.

  2. Книга "Pro Git" — must-read для глубокого понимания работы Git.

Надеюсь, мой опыт будет вам полезен. Буду рад вопросам и комментариям!