Usuń duży plik .pack utworzony przez git


112

Sprawdziłem załadowane pliki w gałęzi i scaliłem, a potem musiałem je usunąć i teraz mam duży plik .pack, którego nie wiem, jak się pozbyć.

Usunąłem wszystkie pliki za pomocą git rm -rf xxxxxxi również uruchomiłem tę --cachedopcję.

Czy ktoś może mi powiedzieć, jak mogę usunąć duży plik .pack, który znajduje się obecnie w następującym katalogu:

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

Czy muszę po prostu usunąć gałąź, którą nadal mam, ale już nie używam? Czy jest jeszcze coś, co muszę uruchomić?

Nie jestem pewien, ile to robi, ale pokazuje kłódkę przy teczce.

Dzięki


EDYTOWAĆ

Oto kilka fragmentów mojej historii bash_history, które powinny dać wyobrażenie, jak udało mi się wejść w ten stan (załóżmy, że w tym momencie pracuję nad gałęzią git o nazwie `` moja-gałąź '' i mam folder zawierający więcej folderów / pliki):

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

Myślałem, że wykonałem również następujące czynności, ale nie pojawia się w bash_history z innymi:

git rm -rf --cached unwanted_folder/

Pomyślałem również, że uruchomiłem kilka poleceń git (takich jak git gc), aby spróbować uporządkować plik pakietu, ale nie pojawiają się one również w pliku .bash_history.


Czy możesz wyjaśnić, w jaki sposób je usunąłeś? Jeśli nadal znajdują się w historii zmian, to nadal są w plikach paczek.
loganfsmyth

Cześć @loganfsmyth, dodałem skrypty historii basha, które, mam nadzieję, pomogą.
user1116573

Odpowiedzi:


201

Problem polega na tym, że nawet jeśli usunąłeś pliki, są one nadal obecne w poprzednich wersjach. O to chodzi w git, nawet jeśli coś usuniesz, nadal możesz to odzyskać, uzyskując dostęp do historii.

To, co chcesz zrobić, nazywa się przepisywaniem historii i obejmowało git filter-branchpolecenie.

GitHub ma dobre wyjaśnienie problemu na swojej stronie. https://help.github.com/articles/remove-sensitive-data

Aby odpowiedzieć na pytanie bardziej bezpośrednio, w zasadzie musisz uruchomić to polecenie z unwanted_filename_or_folderodpowiednio zastąpionym:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

Spowoduje to usunięcie wszystkich odniesień do plików z aktywnej historii repozytorium.

Następny krok, aby wykonać cykl GC w celu wymuszenia wygaśnięcia wszystkich odwołań do pliku i usunięcia go z pliku pakietu. W tych poleceniach nie trzeba nic zmieniać.

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

3
Oznaczyłem to jako zaakceptowane, jeśli to ułatwi każdemu, kto przyjdzie do tego pytania w przyszłości, chociaż faktycznie rozwiązałem wtedy swój problem, tworząc nowe repozytorium git
user1116573

3
Nie wiem, jak to wymyśliłeś, ale ... Ty jesteś mężczyzną. Dzięki.
Ezekiel Victor

5
Ta odpowiedź wskazała mi właściwy kierunek. Ale aby faktycznie usunąć pliki, potrzebne są jeszcze 3 polecenia 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2) git reflog expire --expire=now --all3)git gc --prune=now
arod

3
Uważam, że używanie jest bfgznacznie łatwiejsze. Jest to również zalecane w oficjalnych dokumentach github: help.github.com/articles/ ...
Timo

2
@Timo Dobrze jest dodać nową odpowiedź, jeśli z czasem coś się zmieniło. Idź po to!
loganfsmyth

12

Scenariusz A : Jeśli duże pliki zostały dodane tylko do gałęzi, nie musisz uruchamiać git filter-branch. Wystarczy usunąć gałąź i uruchomić czyszczenie pamięci:

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

Scenariusz B : Jednak na podstawie historii basha wygląda na to, że scaliłeś zmiany w master. Jeśli nikomu nie udostępniłeś zmian ( git pushjeszcze nie ). Najłatwiej byłoby zresetować master z powrotem do stanu sprzed scalenia z gałęzią, która zawiera duże pliki. Spowoduje to wyeliminowanie wszystkich zatwierdzeń z twojej gałęzi i wszystkich zatwierdzeń dokonanych do mastera po scaleniu. Więc możesz stracić zmiany - oprócz dużych plików - które mogłeś chcieć:

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

Następnie wykonaj kroki ze scenariusza A.

Scenariusz C : Jeśli po scaleniu nastąpiły inne zmiany z gałęzi lub zmiany na wzorcu, które chcesz zachować, najlepiej byłoby zmienić bazę danych nadrzędnych i wybiórczo dołączyć wybrane zmiany:

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

W swoim edytorze usuń wiersze odpowiadające zatwierdzeniom, które dodały duże pliki, ale pozostaw wszystko inne bez zmian. Zapisz i wyjdź. Twoja gałąź główna powinna zawierać tylko to, co chcesz, bez dużych plików. Zwróć uwagę, że git rebasebez -ptego usunie się scalanie zatwierdzeń, więc pozostaniesz z liniową historią dla mastera po <commit hash>. Prawdopodobnie jest to dla ciebie w porządku, ale jeśli nie, możesz spróbować -p, ale git help rebasemówi combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

Następnie uruchom polecenia ze scenariusza A.


Istnieje wariant scenariusza A tu z jednak dodatkowy nieoczekiwany problem.

Scenariusz Rozwiązany problem kopalni, aby usunąć dużą ilość tymczasowego pliku pakietu. Repozytorium było zarządzane przez serwer kompilacji i powoduje tworzenie niechcianych plików w folderze .git / objects / pack. Mogłem zwolnić cenne GB z mojego dysku.
xrissz

7

Jak już loganfsmyth stwierdził w swojej odpowiedzi , musisz wyczyścić historię git, ponieważ pliki nadal tam istnieją, nawet po usunięciu ich z repozytorium. Oficjalna dokumentacja GitHub poleca BFG, który jest dla mnie łatwiejszy w użyciu niż filter-branch:

Usuwanie plików z historii

Pobierz BFG z ich strony internetowej. Upewnij się, że masz zainstalowaną Javę, a następnie utwórz kopię lustrzaną i wyczyść historię. Pamiętaj, aby zastąpić YOUR_FILE_NAMEnazwą pliku, który chcesz usunąć:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

Usuń folder

To samo co powyżej, ale użyj --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

Inne opcje

BFG pozwala również na jeszcze bardziej wyszukane opcje (patrz dokumentacja ), takie jak te:

Usuń z historii wszystkie pliki większe niż 100 MB:

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

Ważny!

Podczas uruchamiania BFG należy uważać, aby obie nazwy YOUR_FILE_NAMEi YOUR_FOLDER_NAMErzeczywiście były tylko nazwami plików / folderów. To nie są ścieżki , więc coś takiego foo/bar.jpgnie zadziała! Zamiast tego wszystkie pliki / foldery o określonej nazwie zostaną usunięte z historii repozytorium, bez względu na ścieżkę lub gałąź, w której istniały.


Zastanawiam się, czy chcę zastosować to bfgnarzędzie do lokalnego repozytorium git, jak powinno wyglądać polecenie?
Angel Todorov

5

Jedna opcja:

uruchomić git gcręcznie, aby skondensować kilka plików paczek w jeden lub kilka plików paczek. Ta operacja jest trwała (tzn. Duży plik paczki zachowa swoje zachowanie kompresji), więc może być korzystne okresowe kompresowanie repozytorium za pomocągit gc --aggressive

Inną opcją jest zapisanie kodu i .git gdzieś, a następnie usunięcie .git i ponowne rozpoczęcie korzystania z tego istniejącego kodu, tworząc nowe repozytorium git ( git init).


Cześć Michael, próbowałem uruchomić git gci przeszedłem do kilku plików paczek, ale duży nadal jest jednym z nich i chciałbym się go pozbyć, aby móc łatwiej wykonać kopię zapasową folderu na zewnątrz (wcześniej zip był 1 -2 MB, teraz 55 MB). Chyba że ktoś może zasugerować cokolwiek innego, myślę, że będę musiał stworzyć świeżego dupka. Zakładam, że to oznacza, że ​​stracę dostęp do gałęzi, które obecnie posiadam itp.?
user1116573

2
Zrezygnowałem z prób i po prostu usunąłem folder .git i utworzyłem nowe repozytorium git, jak powiedziałeś. Potraktuję to jako lekcja. Dzięki Michael.
user1116573

4
To nie ma większego sensu. Dlaczego nie możesz po prostu powiedzieć gitowi, aby skonsolidował bieżące repozytorium i usunął pliki pakietu w tym procesie?
jml

4

Uruchom następujące polecenie, zastępując PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAścieżkę do pliku, który chcesz usunąć, a nie tylko jego nazwę. Te argumenty:

  1. Wymuś przetwarzanie przez Git, ale nie sprawdzanie całej historii każdej gałęzi i tagu
  2. Usuń określony plik, a także wszelkie puste zatwierdzenia wygenerowane w rezultacie
  3. Zastąp istniejące tagi
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

Spowoduje to wymuszenie usunięcia wszystkich odniesień do plików z aktywnej historii repozytorium.

Następny krok, aby wykonać cykl GC w celu wymuszenia wygaśnięcia wszystkich odniesień do pliku i usunięcia go z pliku pakietu. W tych poleceniach nie trzeba nic zmieniać.

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

W końcu z drugiej części uzyskałem repozytorium 28G do 158M. Prawie nic innego w Google nie działało. Dziękuję Ci.
Sridhar Sarnobat

Wykonałem powyższe kroki i nacisnąłem jako „git push origin --force --all”, a mimo to moje zdalne gałęzie (master, develop i feature / ASD-1010) nie zostały wyczyszczone. Kiedy świeżo sklonowałem ze zdalnego repozytorium, pliki .pack były nadal obecne. Jak mogę odzwierciedlić to czyszczenie we wszystkich zdalnych gałęziach git?
Sambit Swain

1

Trochę się spóźniłem na pokaz, ale jeśli powyższa odpowiedź nie rozwiązała pytania, znalazłem inny sposób. Po prostu usuń określony duży plik z .pack. Miałem ten problem, w którym przypadkowo wpisałem duży plik 2 GB. Postępowałem zgodnie z instrukcjami podanymi w tym linku: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/


Po wykonaniu tej metody całkowicie usunie całą historię projektu lub po prostu usunie określony plik.
Samim Aftab Ahmed

-3

jest to bardziej poręczne rozwiązanie niż kodowanie. spakuj plik. Otwórz plik zip w formacie widoku pliku (różnym od rozpakowywania). Usuń plik .pack. Rozpakuj i zamień folder. Działa jak marzenie!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.