Oczyść historię Gita, część 2

Poufne dane lub zbyt duże zużycie pamięci: istnieją dobre powody, aby chcieć zmienić historię Git. W tym poście na blogu wyjaśniłem, jak usunąć pliki z historii Git przy użyciu BFG . Słabym punktem BFG jest brak obsługi ścieżek bezpośrednich , przez co nie można specjalnie usuwać z historii plików lub folderów w podfolderach. Po tym nadszedł czas, aby przyjrzeć się alternatywnym rozwiązaniom.


Oprócz oficjalnie niezalecanej gałęzi git filter git-filter-repo jest jednym z narzędzi do czyszczenia historii. Po krótkiej instalacji najpierw analizujemy repozytorium i znajdujemy np. największe foldery w historii:

git filter-repo --analyze

Bądź w folderze .git/filter-repo/analysis wygenerował wszystkie rodzaje plików TXT:

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

Warto plik directories-all-sizes.txt przyjrzyj się bliżej:

=== 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
...

Często zdarza się, że od dawna zignorowałeś i usunąłeś z HEAD dane w historii (na przykład folder multimediów WordPressa) wp-content/uploads/ lub przypadkowo popchnięty node_modules- lub vendor-Spoiwo).

Ogólnie poleca git-filter-repo po oczyszczeniu, wypchnięcie do nowego, pustego repozytorium. Istnieje wiele powodów wymienionych tutaj, dlaczego ma to sens i pozwala uniknąć wielu problemów. Niemniej jednak może się zdarzyć, że chcesz wypchnąć do tego samego repozytorium i jest to również możliwe z kilkoma wskazówkami.

Co ważne, główne platformy hostingowe kodu GitHub oraz GitLab polecam różne podejścia, z których niektóre różnią się od siebie. Na przykład na GitHub usuwamy wp-content/uploads/ wykonując następujące czynności git-filter-repo z historii:

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

Teraz możemy również sprawdzić rozmiar zdalnie (zmiana rozmiaru przez API i w interfejsie użytkownika może zająć do 24 godzin). Aby to zrobić, otwórz ustawienia repozytorium (jeśli repozytorium należy do organizacji, musisz najpierw dodać własne konto do organizacji). Teraz widzimy rozmiar:

GitHub: miejsce na dysku przed czyszczeniem
GitHub: miejsce na dysku po czyszczeniu

Procedura jest nieco inna na 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

Po kolejnym oczekiwaniu ~5 minut możemy zejść pod Settings > Usage Quotas zobacz miejsce do przechowywania:

GitLab: miejsce na dysku przed czyszczeniem
GitLab: miejsce na dysku po czyszczeniu

Po usunięciu ważne jest, aby wszyscy zaangażowani programiści byli zaangażowani w ostatnie kroki: jeśli użytkownik wykona teraz normalne push z własną lokalną kopią, spowoduje to migrację dużych plików z powrotem do centralnego repozytorium. Dlatego zalecane są następujące 3 opcje:

  • "świeży klon biednego człowieka"
    • rm -rf .git && git clone xxx temp && mv temp/.git ./.git && rm -rf temp
    • Dla zmienionych plików (w zależności od aplikacji): git checkout -- . lub. git add -A . && git commit -m "Push obscure file changes." && git push
  • "zaczynać od początku"
    • rm -rf repo && git clone xxx .
  • „brzydkie ciągnięcie z rebasem”
    • git pull -r
    • Tutaj nadal masz nieoczyszczoną historię, ale w większości przypadków nie nadpisujesz już przypadkowo zdalnego repozytorium dużym wariantem lokalnym

W trakcie obecnych kwot (szczególnie ze względu na nowe ograniczenia GitLab ) zawsze warto sprawdzić rozmiar historii swoich repozytoriów i w razie potrzeby je wyczyścić:

GitHub za darmoBezpłatne GitLab
Maksymalny rozmiar pliku100MB
Maksymalny limit rozmiaru repo5000 MB
Maksymalny limit liczby repo
Maksymalny całkowity limit rozmiaru5000 MB

Na koniec warto również przyjrzeć się samodzielnemu, darmowemu wariantowi, takiemu jak Gitea rzucić. Przy niewielkim wysiłku możesz na bardzo cienki serwer samoobsługowa instancja Git (GUI per SSL zabezpieczone, Utworzyć kopię zapasową w cenie, kontrola nad potężne API) gospodarz, które również są doskonałe skonfigurować i jest również lepszy pod względem ochrony danych. Tutaj przy okazji możesz również użyć git-filter-repo Po prostu usprawnij repozytoria:

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

Tutaj konkretnie jest polecenie sudo -u git git gc --aggressive --prune=now ważne (działający cron git gc inaczej ma jeden za długi czas suszonych śliwek 2 tygodnie).

Plecy