Как быстро удалить большие файлы, пароли или личные данные из истории Git?

Как очистить историю Git, если вы допустил ошибку, передав большие файлы в репозиторий, который теперь начинает расти в геометрической прогрессии? А что если произошла утечка конфиденциальных данных? Очевидно, что файлы не могут быть легко удалены из репозитория. Нельзя просто зайти в хранилище, отметить ненужное и нажать <delete>

BFG Repo-Cleaner удаляет большие объектные файлы (блобы) и конфиденциальную информацию. Как утверждает автор, Роберто Тайли, BFG работает от 10 до 720 раз быстрее git-filter-branch.

BFG требует наличия Java 7 начиная с версии 1.1.5.5.

В документации говорится, что нужно клонировать репозиторий с параметром --mirror, который на самом деле не нужен, если у вас уже есть проект со всеми основными ветками.

Предположим, что путь к репозиторию следующий: /Users/eu/myproject.

Для начала работы необходимо скачать bfg-файл и разместить jar вне папки myproject.

Попробуем удалить большие файлы (пусть это будут файлы размером более 10 Мб) и затереть случайно упомянутые пароли в одном из файлов (secrets.txt). С каждой операцией инструмент будет перезаписывать хеш коммита. Вы получите соответствие между старым и новым коммитами. Важно знать, что последний коммит защищен и гарантируется, что все находящиеся в нем файлы сохранятся.

Найдем искомые файлы и удалим их из истории (но не физически):

$ java -jar bfg.jar --strip-blobs-bigger-than 10M myproject.git

Заменим все пароли, случайно упомянутые в secrets.txt, на строку ***REMOVED***:

$ bfg --replace-text secrets.txt myproject.git

Удалим старые записи reflog и запустим сборщик мусора:

$ git reflog expire --expire=now --all && git gc --prune=now --aggressive

После выполнения этой команды файлы будут удалены физически.

Выполним мерж локальных изменений в удаленный репозиторий:

$ git push origin <your-branch> --force

Теперь, зайдя в удаленный репозиторий, вы обнаружите, что его размер не уменьшился, а только вырос. Не переживайте, это нормальная ситуация. Дело в том, что предпринятые действия добавили новый репозиторий поверх старого. Теперь нужно запустить сборщик мусора в удаленном репозитории, чтобы он сделал то же, что мы делали локально.

Следующие команды заставят git запустить сборщик мусора (git gc):

$ git reset --hard HEAD~1
$ git push --force

Если кому-то еще будет нужно получить данные из репозитория, понадобится форсировать pull и выполнить git reset --hard origin <your-branch>.