Nie można przesłać do GitHub z powodu dużego pliku, który już usunąłem

272

Obecnie mam

  1. Puste repozytorium GitHub
  2. Repozytorium serwerów SSH (główne)
  3. Lokalne repozytorium

Repozytorium serwera SSH było najbardziej aktualnym repozytorium (strona produkcyjna), więc zrobiłem klon Git stamtąd na lokalny. Następnie próbowałem zrobić git pushGitHub.

Wszystko poszło dobrze, ale wtedy coś mówiło o tym, że filename.gz jest zbyt duży dla GitHub. Nie potrzebowałem tego pliku, więc uruchomiłem kilka poleceń Git, aby pozbyć się go z pamięci podręcznej Git, a następnie zepchnąłem z powrotem na serwer SSH.

Nie widzę dużego pliku lokalnie, ale nadal znajduje się na serwerze SSH, mimo że git diffnic nie zwraca, a git push zwraca „Wszystko jest aktualne” - I chociaż plik nie jest widoczny w lokalnym repozytorium, gdy próbuję przepchnąć GitHub Nadal pojawia się błąd

zdalny: błąd: plik fpss.tar.gz ma 135,17 MB; przekracza to limit rozmiaru pliku GitHub wynoszący 100 MB

Postępowałem zgodnie z instrukcjami podanymi w sekcji „Rozwiązywanie problemu” wymienionymi w pomocy GitHub, więc czy to nie powinno wystarczyć?

W jaki sposób plik jest nadal w eterze, gdy nie jest lokalny lub nie ma go na liście git status / diff / push?

Kevin W.
źródło
2
Plik jest nadal w historii. Musisz zniszczyć historię, prawdopodobnie przez zmiażdżenie zatwierdzeń, które dodały i usunęły plik.
Shahbaz
@Shahbaz Wykonałem czynności opisane w sekcji „Rozwiązywanie problemu” na tej stronie ... czy to nie powinno wystarczyć? help.github.com/articles/working-with-large-files
Kevin W.
Polecenie tam jest bardziej zaawansowane niż moja znajomość git, więc tak naprawdę nie mogę powiedzieć. W każdym razie, jeśli git log -- the_big_filecoś ci zwróci, plik jest nadal w historii.
Shahbaz
@Shahbaz, który zwraca nic> <
Kevin W.
Czy to możliwe, że wypychasz także inne gałęzie, w których plik istnieje? Ponadto, jeśli plik nadal znajduje się na serwerze, dlaczego miałby git pushmówić , że wszystko jest aktualne? Ponieważ zmieniłeś historię, powinieneś narzekać, że wypychanie nie jest możliwe i że musisz go zmusić.
Shahbaz

Odpowiedzi:

446

Możesz użyć

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch <file/dir>' HEAD

Spowoduje to usunięcie wszystkiego w historii tego pliku. Problem polega na tym, że plik jest obecny w historii.

To polecenie zmienia skróty twoich zatwierdzeń, co może być prawdziwym problemem, szczególnie w przypadku współdzielonych repozytoriów. Nie należy tego robić bez zrozumienia konsekwencji.

MacGyver
źródło
23
Pracowałem dla mnie, ale musiałem to „wymusić”: git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch <plik / katalog>' -f HEAD
alexoviedo999
30
To polecenie zmienia skróty twoich zatwierdzeń, co może być prawdziwym problemem, szczególnie w przypadku współdzielonych repozytoriów. Nie należy tego robić bez zrozumienia konsekwencji.
Chris
6
Czy powinieneś zastąpić <file / dir> nazwą pliku lub dir, który powoduje problem?
David Rhoden,
12
Pamiętaj, że jeśli chcesz zastosować te zmiany do WSZYSTKICH gałęzi, musisz użyć --allflagi zamiastHEAD
Nick Spreitzer,
9
Dostaję:Rewrite 657560fa18c030bcfac9132ce1c3541e84a5bc2c (1/10) (0 seconds passed, remaining 0 predicted) /usr/lib/git-core/git-filter-branch: 1: eval: Syntax error: end of file unexpected
João Abrantes
68

Uważam, że squashowanie jest bardziej przydatne niż filter-branch. Zrobiłem następujące:

  1. Lokalnie usuwaj duże pliki.
  2. Zatwierdź lokalne usuwanie.
  3. Miękki reset liczba powrotem X zobowiązuje (dla mnie było to 3) git reset --soft HEAD~3.
  4. Następnie ponownie uruchom wszystkie zmiany razem (squash AKA) git commit -m "New message for the combined commit"
  5. Push squashhed commit.

Przypadek specjalny (od użytkownika @lituo): Jeśli powyższe nie działa, możesz mieć ten przypadek. Zatwierdzenie 1 obejmowało duży plik, a wypychanie zatwierdzenia 1 nie powiodło się z powodu błędu dużego pliku. Zatwierdzenie 2 usunęło duży plik,git rm --cached [file_name]ale wypychaniezatwierdzenia2 nadal nie powiodło się. Możesz wykonać te same kroki powyżej, ale zamiast używaćHEAD~3, użyjHEAD~2.

Ale ja nie jestem klasą otoki
źródło
2
Pracowałem dla mnie, musiałem ponownie scalić zmiany z trzech commits z powrotem do mojego lokalnego repozytorium, zanim zadziałało push push.
dasWesen
5
To DUŻO lepiej niż najlepsza odpowiedź. Najlepsza odpowiedź psuje całą historię zatwierdzeń.
manic.coder
Nie naprawiłem mojego problemu
Hirak Sarkar,
3
Jest to zdecydowanie jedyna odpowiedź, która naprawia duże niezaangażowane lub zatwierdzone pliki, bez całkowitego niszczenia repozytorium! Pozytywne, aby mógł przejść na górę :-)
Feblex
1
@Ale nie jestem klasą otoki: dziękuję bardzo! to działało jak urok :)
POOJA GUPTA
62

Oto coś, co uważam za bardzo pomocne, jeśli już bawiłeś się swoim repozytorium, zanim poprosiłeś o pomoc. Pierwszy typ:

git status

Po tym powinieneś zobaczyć coś wzdłuż linii

On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

Ważną częścią są „2 zobowiązania”! Stąd śmiało i wpisz:

git reset HEAD~<HOWEVER MANY COMMITS YOU WERE BEHIND>

Tak więc w powyższym przykładzie można wpisać:

git reset HEAD~2

Po wpisaniu tego, twój „status git” powinien powiedzieć:

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

Stamtąd możesz usunąć duży plik (zakładając, że jeszcze tego nie zrobiłeś) i powinieneś być w stanie ponownie wszystko zatwierdzić bez utraty pracy.
Wiem, że to nie jest super fantazyjna odpowiedź, ale mam nadzieję, że to pomoże!

Shreya
źródło
11
Zwycięzca. Proste, czyste, skuteczne rozwiązanie oparte na git. Uwielbiam takie odpowiedzi.
Reece Daniels,
3
to najlepsze dostępne rozwiązanie.
wrahool,
40

Jeśli plik został dodany przy użyciu ostatniego zatwierdzenia i nie przeszedłeś do zdalnego repozytorium , możesz usunąć plik i zmienić zatwierdzenie, pobrane stąd :

git rm --cached giant_file
    # Stage "giant_file" for removal with "git rm"
    # Leave it on disk with "--cached". if you want to remove it from disk
    # then ignore the "--cached" parameter
git commit --amend -CHEAD
    # Commit the current tree without the giant file using "git commit"
    # Amend the previous commit with your change "--amend" 
    # (simply making a new commit won't work, as you need
    # to remove the file from the unpushed history as well)
    # Use the log/authorship/timestamp of the last commit (the one we are
    # amending) with "-CHEAD", equivalent to --reuse-message=HEAD
git push
    # Push our rewritten, smaller commit with "git push"
BlueMoon93
źródło
1
To rozwiązanie nie działa, ponieważ plik nie jest już w indeksie git (wynika z untrackedlisty plików o git status.
loretoparisi
Nic się nie dzieje. Po zastosowaniu zmniejszyło to całkowitą liczbę plików, ale po wyświetleniu procesu 99% ponownie utknęło. Wszelkie sugestie, których mi brakuje?
CoDe,
4
co oznacza -CHEAD?
Aerin
1
Co jeśli chcę wypróbować to z konkretnego zatwierdzenia - nie z ostatniego zatwierdzenia? Próbowałem, git rm --cached giant_file commit_idale to nie zadziałało :(
puifais
@puifais Chciałbym wrócić do poprzedniego zatwierdzenia, wykonać te kroki, a następnie scalić z bieżącym. Nie jestem pewien, czy to najlepsze podejście, nie jestem ekspertem od Git
BlueMoon93,
13

Miałem podobny problem i użyłem powyższego kroku, aby usunąć plik. Działa idealnie.

Następnie dostałem błąd w drugim pliku, który musiałem usunąć: remote: error: File <path/filename> is 109.99 MB; this exceeds GitHub's file size limit of 100.00 MB

Próbowałem tego samego kroku, wystąpił błąd: "A previous backup already exists in <path/filename>"

Z badań na tej stronie użyłem polecenia:git filter-branch --force --index-filter "git rm --cached --ignore-unmatch <path/filename>" --prune-empty --tag-name-filter cat -- --all

Działa świetnie, a duże pliki zostały usunięte.

Niewiarygodnie, wypychanie nadal nie powiodło się z kolejnym błędem: error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 104 fatal: The remote end hung up unexpectedly

Naprawiłem to, modyfikując bezpośrednio plik konfiguracyjny .git - postBuffer = 999999999

Następnie przeszedł nacisk!

Andre Odendaal
źródło
1
dodatkowym problemem, z którym musiałem się zmagać przy usuwaniu dużego pliku (jak wyżej) było to, że jeden z folderów zawierał znak krzyżyka #. Nie spowodowało to żadnych problemów w przypadku normalnej operacji git, jednak dla git rmI musiałem podać pełną nazwę ścieżki repozytorium dla pliku i uciec od znaku # z odwrotnym ukośnikiem, aby go
uruchomić
to również działało dla mnie. Uniknąłem reset hardkroku na dole strony za pomocą prostego naciśnięcia. czettner.com/2015/07/16/…
Monte Hayward
Działa to
12

Dlaczego GitHub odrzuca moje repozytorium, nawet po usunięciu dużego pliku?

Git przechowuje pełną historię twojego projektu, więc nawet jeśli „usuniesz” plik z projektu, repozytorium Git nadal ma kopię tego pliku w swojej historii, a jeśli spróbujesz przepchnąć się do innego repozytorium (na przykład hostowanego w GitHub), a następnie Git wymaga, że repozytorium zdalne ma tę samą historię, co repozytorium lokalne (tj. Te same duże pliki w swojej historii).

Jak mogę zmusić GitHub do zaakceptowania mojego repo?

Musisz wyczyścić lokalnie historię projektu Git, usuwając niechciane duże pliki z całej historii, a następnie używać tylko „wyczyszczonej” historii. Identyfikatory zatwierdzeń Git zatwierdzonych zmian ulegną zmianie.

Jak wyczyścić duże pliki z mojego repozytorium Git?

Najlepszym narzędziem do usuwania niechcianych dużych plików z historii Git jest BFG Repo-Cleaner - jest to prostsza, szybsza alternatywa git-filter-branchspecjalnie zaprojektowana do usuwania niechcianych plików z historii Git.

Dokładnie postępuj zgodnie z instrukcjami użytkowania , podstawowa część jest taka:

$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git

Wszelkie pliki o rozmiarze przekraczającym 100 MB (które nie są w twoim ostatnim zatwierdzeniu) zostaną usunięte z historii repozytorium Git. Następnie możesz użyć git gcdo usunięcia martwych danych:

$ git gc --prune=now --aggressive

BFG jest zazwyczaj co najmniej 10-50 razy szybszy niż bieganie git-filter-branchi ogólnie jest o wiele łatwiejszy w użyciu.

Pełne ujawnienie: jestem autorem BFG Repo-Cleaner.

Roberto Tyley
źródło
1
Moja sprawa miała dodatkowe komplikacje, które wykluczały zgniatanie. Narzędzie BFG działało świetnie. Dzięki.
dantopa
To fenomenalne rozwiązanie
SexualPotatoes
4

Mam ten sam problem i żadna z odpowiedzi nie działa dla mnie. Rozwiązałem następujące kroki:

1. Znajdź, które zatwierdzenie (zatwierdzenia) zawiera duży plik

git log --all -- 'large_file`

Dolne zatwierdzenie jest najstarszym zatwierdzeniem na liście wyników.

2. Znajdź ten tuż przed najstarszym.

git log

Załóżmy, że masz:

commit 3f7dd04a6e6dbdf1fff92df1f6344a06119d5d32

3. Git rebase

git rebase -i 3f7dd04a6e6dbdf1fff92df1f6344a06119d5d32

Wskazówki :

  1. Element listy
  2. Właśnie wybrałem, dropbo commits zawiera duży plik.
  3. Możesz napotkać konflikty podczas rebase, napraw je i używaj, git rebase --continueaby kontynuować aż do jego zakończenia.
  4. Jeśli coś poszło nie tak podczas rebase, użyj go, git rebase --abortaby anulować.
William Hu
źródło
4

Wypróbowałem wszystkie powyższe metody, ale żadna z nich nie działa dla mnie.

Potem wymyśliłem własne rozwiązanie.

  1. Przede wszystkim potrzebujesz czystego, aktualnego repozytorium lokalnego. Usuń wszystkie pieprzone duże pliki.

  2. Teraz utwórz nowy folder NA ZEWNĄTRZ folderu repozytorium i użyj „Git create repository here”, aby uczynić go nowym repozytorium Git, nazwijmy go new_local_repo. To jest to! Wszystkie powyższe metody mówiły, że musisz wyczyścić historię ... cóż, mam tego dość, stwórzmy nowe repozytorium, które w ogóle nie ma historii!

  3. Skopiuj pliki ze starej, spieprzonej lokalnej repozytorium do nowej, pięknej repozytorium. Pamiętaj, że zielone logo na ikonie folderu zniknie, jest to obiecujące, ponieważ jest to nowe repo!

  4. Zatwierdź do lokalnego oddziału, a następnie wypchnij do zdalnego nowego oddziału. Nazwijmy to new_remote_branch. Jeśli nie wiesz, jak wypchnąć nowe lokalne repozytorium, zrób to Google.

  5. Gratulacje! Przesłałeś swój czysty, aktualny kod do GitHub. Jeśli nie potrzebujesz już zdalnej gałęzi master, możesz uczynić swoją gałąź new_remote_branch nową gałęzią master. Jeśli nie wiesz, jak to zrobić, Google go.

  6. Na ostatnim etapie nadszedł czas, aby usunąć pieprzone stare lokalne repozytorium. W przyszłości będziesz korzystać tylko z new_local_repo.

Shuaibin Chang
źródło
1

Rozwiązanie do przechowywania dużych plików / folderów w folderze roboczym

Oto linia, która zadziałała w celu rozwiązania problemu zadanego tutaj (od odpowiedzi 1):

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch <file/dir>' HEAD

To polecenie usuwa również plik / katalog, jeśli plik / katalog znajduje się w działającym drzewie.

Jeśli chcesz zachować plik / folder w działającym drzewie, proponuję wykonać następujące kroki.

  1. Po tym błędzie uruchom git reset HEAD^
  2. Dodaj dany plik / folder do pliku `` .gitignore ''.

  3. Postępuj jak zwykle, git add .co może przechwytywać inne pliki / foldery, ale musi przechwytywać .gitignoreplik. Dalej jest git commit -m"message"i nareszciegit push origin <branch_name>

Kiprono Elijah Koech
źródło
0

to działało dla mnie. dokumentacja z github Squashing Git Commits git reset origin / master

git checkout master && git pull;
git merge feature_branch;
git add . --all;
git commit -m "your commit message"

znajdź dokumentację tutaj

Njoroge Mathu
źródło
0

Dodaję do pierwszej odpowiedzi.

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch' HEAD

Wystąpi konflikt scalania z pochodzenia / wzorca.

Twoja gałąź i „origin / master” są rozbieżne i mają odpowiednio 114 i 109 różnych zatwierdzeń. (użyj „git pull”, aby połączyć zdalną gałąź z twoją)

Uruchom to

git reset - twarde pochodzenie / master

Odrzuci wszystkie moje inscenizowane i nieetapowe zmiany, zapomni o wszystkim w moim obecnym oddziale lokalnym i sprawi, że będzie dokładnie taki sam jak origin / master.

RAHUL KUMAR
źródło
0

Tak więc napotkałem szczególną sytuację: sklonowałem repozytorium z gitlab, które zawierało plik większy niż 100 MB, ale zostało usunięte w pewnym momencie historii git. Później, kiedy dodałem nowe prywatne repozytorium github i próbowałem wypchnąć nowe repo, otrzymałem niesławny błąd „zbyt duży plik”. W tym momencie nie miałem już dostępu do oryginalnego repozytorium gitlab. Nadal byłem jednak w stanie przesłać do nowego prywatnego repozytorium github przy użyciu bfg-repo-cleanerrepozytorium LOCAL na moim komputerze:

$ cd ~
$ curl https://repo1.maven.org/maven2/com/madgag/bfg/1.13.0/bfg-1.13.0.jar > bfg.jar
$ cd my-project
$ git gc
$ cd ../
$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-project
$ cd my-project
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
$ git remote -v # confirm origin is the remote you want to push to
$ git push origin master
Donato
źródło
0

Czasami plik jest przechowywany w historii śledzenia, spróbuj wykonać następujące czynności:

  1. git commit, Jeśli widzisz tryb tworzenia z wymienionym dużym plikiem, wykonaj następujące czynności:
  2. git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch filename' HEAD. Powinieneś zobaczyć kilka Rewrites pokazanych w konsoli, które kończą się na:

    rm „nazwa pliku” i

    ostatnia linia Ref została przepisana.

Zrobione.

Drzewo DR
źródło