Очистка истории Git, часть 2

Конфиденциальные данные или чрезмерное потребление места для хранения: есть веские причины изменить историю Git. В этом сообщении блога я объяснил, как удалять файлы из истории Git с помощью BFG . Слабым местом BFG является отсутствие поддержки прямых путей , поэтому вы не сможете специально удалить из истории файлы или папки в подпапках. Пришло время рассмотреть альтернативные решения.


Помимо официально нерекомендуемой ветки `git filter` , `git-filter-repo` — один из инструментов для очистки истории. После быстрой установки мы сначала анализируем репозиторий и находим, например, самые большие папки в истории.:

git filter-repo --analyze

Хорошо быть в папке .git/filter-repo/analysis генерируются всевозможные файлы TXT:

  • directories-all-sizes.txt
  • extensions-all-sizes.txt
  • path-all-sizes.txt
  • ...

Это стоит файла directories-all-sizes.txt присмотрись повнимательнее:

=== All directories by reverse size ===

Format: unpacked size, packed size, date deleted, directory name

  4624417043 3796607988 <present> <toplevel>
  4475940396 3778033787 <present> wp-content
  4060236681 3694449320 <present> wp-content/uploads
   305163809   70576241 <present> wp-content/plugins
   123818107   15442735 <present> wp-includes
...

Часто бывает, что вы давно игнорировали и удаляли из HEAD данные в истории (например, папку медиафайлов WordPress wp-content/uploads/ или случайно толкнутый node_modules- или vendor- связующее).

Обычно рекомендует git-filter-repo после очистки пушим в новый, пустой репозиторий. Здесь перечислено множество причин, почему это имеет смысл и позволяет избежать многих проблем. Тем не менее, может случиться так, что вы захотите отправить в тот же репозиторий, и это также возможно с помощью нескольких подсказок.

Важно отметить, что основные платформы для размещения кода GitHub а также GitLab Рекомендуйте подходы, которые иногда отличаются друг от друга. На GitHub мы удаляем wp-content/uploads/ например с git-filter-repo в следующих шагах из истории:

mkdir tmp-repo
cd tmp-repo
git clone git@github.com:foo/bar.git .
cp .git/config /tmp/config-backup
git filter-repo --invert-paths --path wp-content/uploads/
# option 1: same repo
  mv /tmp/config-backup .git/config
  git push origin --force --all
# option 2: new repo
  git remote add origin git@github.com:foo/bar-new.git
  git push origin --force --all
cd ..
rm -rf tmp-repo

Теперь мы также можем проверить размер удаленно (изменение размера через API и в пользовательском интерфейсе может занять до 24 часов). Для этого откройте настройки репозитория (если репозиторий принадлежит организации, необходимо предварительно добавить в организацию собственную учетную запись). Теперь мы видим размер:

GitHub: место на диске перед очисткой
GitHub: место на диске после очистки

Процедура немного отличается на GitLab:

mkdir tmp-repo
cd tmp-repo
# option 1: same repo
  # Settings > General > Advanced > Export project > download tar.gz file into tmp-repo
  tar xzf 20*.tar.gz
  git clone --bare --mirror project.bundle
  cd project.git
  git filter-repo --invert-paths --path wp-content/uploads/
  cp ./filter-repo/commit-map /tmp/commit-map-1
  # copying the commit-map has to be done after every single command from git filter-repo
  # you need the commit-map files later
  git remote remove origin
  git remote add origin git@gitlab.com:foo/bar.git
  # Settings > Repository > Protected branches/Protected branches >
  # enable "Allowed to force push to main/master"
  git push origin --force 'refs/heads/*'
  git push origin --force 'refs/tags/*'
  git push origin --force 'refs/replace/*'
  # Settings > Repository > Protected branches/Protected branches >
  # disable "Allowed to force push to main/master"
  date
  # wait 30 minutes (😱)
  date
  # Settings > Repository > upload /tmp/commit-map-X
# option 2: new repo
  git clone git@gitlab.com:foo/bar.git .
  git filter-repo --invert-paths --path wp-content/uploads/
  git remote add origin git@gitlab.com:foo/bar-new.git
  # Settings > Repository > Protected branches/Protected branches >
  # enable "Allowed to force push to main/master"
  git push origin --force --all
  # Settings > Repository > Protected branches/Protected branches >
  # disable "Allowed to force push to main/master"
cd ..
rm -rf tmp-repo

После еще одного ожидания ~ 5 минут мы можем уйти Settings > Usage Quotas посмотреть место для хранения:

GitLab: место на диске перед очисткой
GitLab: место на диске после очистки

После удаления важно, чтобы все вовлеченные разработчики участвовали в последних шагах: если пользователь сейчас выполнит обычную отправку своей собственной локальной копии, это приведет к переносу больших файлов обратно в центральный репозиторий. Поэтому рекомендуются следующие 3 варианта:

  • "свежий клон бедняги"
    • rm -rf .git && git clone xxx temp && mv temp/.git ./.git && rm -rf temp
    • Для измененных файлов (в зависимости от приложения): git checkout -- . или же. git add -A . && git commit -m "Push obscure file changes." && git push
  • "начинать с нуля"
    • rm -rf repo && git clone xxx .
  • "уродливая тяга с перебазированием"
    • git pull -r
    • Здесь неочищенная история по-прежнему восстанавливается, но в большинстве случаев удаленный репозиторий больше не перезаписывается случайно большой локальной версией.

В ходе текущих квот (особенно из-за новых ограничений GitLab ) всегда стоит проверять размер истории ваших репозиториев и подчищать их при необходимости:

GitHub БесплатноGitLab Бесплатно
Максимальный размер файла100 МБ∞
Максимальный размер репо5000 МБ∞
Максимальный лимит количества репо∞∞
Максимальный общий размер∞5000 МБ

Наконец, также стоит взглянуть на самостоятельный бесплатный вариант, такой как Гитея бросать. С небольшими усилиями вы можете на очень тонкий сервер самостоятельный экземпляр Git (графический интерфейс на SSL обеспеченный, Резервное копирование включены, контроль над мощный API) host, которые тоже отличные настроить а также лучше с точки зрения защиты данных. Здесь, кстати, тоже можно использовать git-filter-repo Просто оптимизируйте репозитории:

mkdir tmp-repo
cd tmp-repo
git clone git@git.tld.com:foo/bar.git .
cp .git/config /tmp/config-backup
git filter-repo --invert-paths --path wp-content/uploads/
# option 1: same repo
  mv /tmp/config-backup .git/config
  git push origin --mirror
  # login on the remote command line and run in the repo-folder
  sudo -u git git reflog expire --expire=now --all
  sudo -u git git gc --aggressive --prune=now
  # if you face memory limit issues, modify the git configuration
  sudo -u git git config --global pack.windowMemory "100m"
  sudo -u git git config --global pack.packSizeLimit "100m"
  sudo -u git git config --global pack.threads "1"
  # if in web ui the size does not change, make a slight
  # modification to a file and push again normally
# option 2: new repo
  git remote add origin git@git.tld.com:foo/bar-new.git
  git push origin --force --all
cd ..
rm -rf tmp-repo

Вот конкретно команда sudo -u git git gc --aggressive --prune=now важно (работает cron git gc в противном случае он слишком длинный сократить время от 2 недель).

Назад