Jak usunąć nieużywane obiekty z repozytorium Git?

89

Przypadkowo dodałem, zatwierdziłem i wrzuciłem ogromny plik binarny z moim najnowszym zatwierdzeniem do repozytorium Git.

Jak sprawić, by Git usunął obiekty, które zostały / zostały utworzone dla tego zatwierdzenia, aby mój .gitkatalog ponownie się zmniejszył do rozsądnego rozmiaru?

Edycja : Dzięki za odpowiedzi; Wypróbowałem kilka rozwiązań. Żaden nie działał. Na przykład ten z GitHub usunął pliki z historii, ale .gitrozmiar katalogu się nie zmniejszył:

$ BADFILES=$(find test_data -type f -exec echo -n "'{}' " \;)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $BADFILES" HEAD
Rewrite 14ed3f41474f0a2f624a440e5a106c2768edb67b (66/66)
rm 'test_data/images/001.jpg'
[...snip...]
rm 'test_data/images/281.jpg'
Ref 'refs/heads/master' was rewritten

$ git log -p # looks nice

$ rm -rf .git/refs/original/
$ git reflog expire --all
$ git gc --aggressive --prune
Counting objects: 625, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (598/598), done.
Writing objects: 100% (625/625), done.
Total 625 (delta 351), reused 0 (delta 0)

$ du -hs .git
174M    .git
$ # still 175 MB :-(
Jonas H.
źródło
13
Tylko przypomnienie dla moderatorów, to pytanie w 100% należy do SO, a nie superużytkownika.
VonC,
Jak wspomniano tutaj ( stackoverflow.com/questions/685319/… ), czy próbowałeś przepakować po gc? git-repack -apo którym następuje git-prune-packedna przykład. Zobacz blog.felipebalbi.com/2007/12/19/…
VonC
2
@Jonas: a co jeśli po wykonaniu tego wszystkiego sklonujesz repozytorium? Czy wtedy uzyskać klon z pożądanym zmniejszonym rozmiarze?
VonC
1
@Jonas: po wszystkim, co zrobił ( filter-branch, gc, repack, ...), nie, nie powinien zobaczyć każdy zły popełnić w ogóle. To znak, że sprzątanie nie odbyło się zgodnie z oczekiwaniami.
VonC

Odpowiedzi:

127

Odpowiedziałem na to gdzie indziej i skopiuję tutaj, ponieważ jestem z tego dumny!

... i bez zbędnych ceregieli, przedstawię wam ten przydatny skrypt, git-gc-all, gwarantujący usunięcie wszystkich śmieci git, dopóki nie wymyślą dodatkowych zmiennych konfiguracyjnych:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
  -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
  -c gc.pruneExpire=now gc "$@"

Pomocna może być opcja --aggressive.

UWAGA: usunie to WSZYSTKIE rzeczy bez odniesień, więc nie przychodź do mnie płacz, jeśli później zdecydujesz, że chcesz zachować niektóre z nich!

Być może będziesz musiał najpierw uruchomić coś takiego, ojej, git jest skomplikowany !!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ |
  xargs -n1 --no-run-if-empty git update-ref -d

Wszystko to umieściłem w scenariuszu, tutaj:

http://sam.nipl.net/b/git-gc-all-ferocious

Sam Watkins
źródło
Tak jak w stackoverflow.com/questions/1904860/… , +1 dla Ciebie ponownie.
VonC,
18
znakomicie: D mój zły plan zdobycia większej liczby punktów przez klonowanie odpowiedzi zadziałał !! 1;)
Sam Watkins
Tak! To zadziałało, ale musiałem uruchomić pełny skrypt. Uruchomienie samej komendy gc (z opcjami konfiguracji) nie wystarczyło.
Daniel,
4
102m do 160k .. efektywne i destrukcyjne
prusswan
4
Wielkie dzięki za scenariusz! Informacje o bonusach: xargspolecenie powoduje błąd w systemie OS X z powodu nierozpoznanej opcji. Najprostsze rozwiązanie: zainstaluj GNU xargs przez homebrew brew install findutilsi zamień xargsna gxargs.
qqilihq
26

Twoje git reflog expire --alljest nieprawidłowe. Usuwa wpisy reflog, które są starsze niż czas wygaśnięcia, który domyślnie wynosi 90 dni. Użyj git reflog expire --all --expire=now.

Moja odpowiedź na podobne pytanie dotyczy problemu rzeczywistego usuwania nieużywanych obiektów z repozytorium.

Josh Lee
źródło
18

1) Usuń plik z repozytorium git (a nie z systemu plików):

  • git rm --cached path/to/file

2) Zmniejsz repozytorium za pomocą:

  • git gc,

  • lub git gc --aggressive

  • lub git prune

lub kombinacja powyższych, jak zasugerowano w tym pytaniu: Zmniejsz rozmiar repozytorium git

Jamie
źródło
10

Ten przewodnik dotyczący usuwania danych wrażliwych może mieć zastosowanie przy użyciu tej samej metody. Będziesz przepisywać historię, aby usunąć ten plik z każdej wersji, w której był obecny. Jest to destrukcyjne i spowoduje konflikty repozytorium z innymi pobraniami, więc najpierw ostrzeż współpracowników.

Jeśli chcesz, aby plik binarny był dostępny w repozytorium dla innych osób, nie ma prawdziwego sposobu na robienie tego, co chcesz. Prawie wszystko albo nic.

Daenyth
źródło
8

Klucz dla mnie okazał się być uruchomiony, git repack -A -d -fa następnie git gczmniejszyć rozmiar pojedynczego pakietu git, który miałem.

Andrzeja Charneskiego
źródło
6

Hy!

Git otrzymuje tylko obiekty, których faktycznie potrzebuje podczas klonowania repozytoriów (jeśli dobrze to rozumiem)

Możesz więc zmienić ostatnie zatwierdzenie, usuwając plik dodany przez pomyłkę, a następnie przesłać zmiany do zdalnego repozytorium (z opcją -f, aby nadpisać również stare zatwierdzenie na serwerze)

Następnie, kiedy tworzysz nowy klon tego repozytorium, jego katalog .git powinien być tak mały, jak przed zatwierdzeniem dużego pliku (i).

Opcjonalnie, jeśli chcesz usunąć również niepotrzebne pliki z serwera, możesz usunąć repozytorium na serwerze i wypchnąć swoją nowo sklonowaną kopię (która ma pełną historię)

u-foka
źródło
4
git filter-branch --index-filter 'git rm --cached --ignore-unmatch Filename' --prune-empty -- --all

Pamiętaj, aby zmienić Filenamena ten, który chcesz usunąć z repozytorium.

Jaskółka oknówka
źródło