Очистка истории 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 недель).

Назад