Rimuovi il file .pack di grandi dimensioni creato da git


112

Ho archiviato un carico di file in un ramo e li ho uniti, quindi ho dovuto rimuoverli e ora mi rimane un file .pack di grandi dimensioni di cui non so come sbarazzarmi.

Ho cancellato tutti i file usando git rm -rf xxxxxxe ho anche eseguito l' --cachedopzione.

Qualcuno può dirmi come posso rimuovere un file .pack di grandi dimensioni che si trova attualmente nella seguente directory:

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

Devo solo rimuovere il ramo che ho ancora ma che non utilizzo più? O c'è qualcos'altro che devo eseguire?

Non sono sicuro di quanta differenza faccia ma mostra un lucchetto contro il file.

Grazie


MODIFICARE

Ecco alcuni estratti dalla mia bash_history che dovrebbero dare un'idea di come sono riuscito a entrare in questo stato (supponi che a questo punto stia lavorando su un ramo git chiamato 'my-branch' e ho una cartella contenente più cartelle / File):

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)

Pensavo di aver eseguito anche quanto segue ma non appare nella bash_history con gli altri:

git rm -rf --cached unwanted_folder/

Ho anche pensato di git gceseguire alcuni comandi git (come ) per provare a riordinare il file pack ma non compaiono nemmeno nel file .bash_history.


Puoi chiarire come li hai rimossi? Se sono ancora nella cronologia dei commit, sono ancora nei file del pacchetto.
loganfsmyth

Ciao @loganfsmyth, ho aggiunto gli script della cronologia di bash che si spera aiuteranno.
user1116573

Risposte:


201

Il problema è che, anche se hai rimosso i file, sono ancora presenti nelle revisioni precedenti. Questo è il punto centrale di git, è che anche se elimini qualcosa, puoi comunque recuperarlo accedendo alla cronologia.

Quello che stai cercando di fare si chiama riscrittura della cronologia e ha coinvolto il git filter-branchcomando.

GitHub ha una buona spiegazione del problema sul proprio sito. https://help.github.com/articles/remove-sensitive-data

Per rispondere alla tua domanda in modo più diretto, ciò che devi fondamentalmente eseguire è questo comando con unwanted_filename_or_foldersostituito di conseguenza:

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

Ciò rimuoverà tutti i riferimenti ai file dalla cronologia attiva del repository.

Passaggio successivo, eseguire un ciclo GC per forzare la scadenza e l'eliminazione di tutti i riferimenti al file dal file di pacchetto. Non è necessario sostituire nulla in questi comandi.

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
L'ho contrassegnato come accettato se ciò rende più facile per chiunque si rivolga a questa domanda in futuro, anche se in realtà ho risolto il mio problema in quel momento creando un nuovo repository git
user1116573

3
Non so come sei arrivato a questo, ma ... Sei tu l'uomo. Grazie.
Ezekiel Victor

5
Questa risposta mi ha indirizzato nella giusta direzione. Ma per eliminare effettivamente i file sono necessari altri 3 comandi 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
Trovo che l'uso sia bfgmolto più semplice. È consigliato anche nei documenti ufficiali di github: help.github.com/articles/…
Timo

2
@Timo È bene aggiungere una nuova risposta, se le cose sono cambiate nel tempo. Fallo!
loganfsmyth

12

Scenario A : se i file di grandi dimensioni sono stati aggiunti solo a un ramo, non è necessario eseguirli git filter-branch. Devi solo eliminare il ramo ed eseguire la garbage collection:

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

Scenario B : Tuttavia, in base alla tua cronologia bash, sembra che tu abbia unito le modifiche in master. Se non hai condiviso le modifiche con nessuno (no git pushancora). La cosa più semplice sarebbe reimpostare il master a prima dell'unione con il ramo che aveva i file grandi. Questo eliminerà tutti i commit dal tuo branch e tutti i commit fatti al master dopo l'unione. Quindi potresti perdere le modifiche, oltre ai file di grandi dimensioni, che potresti aver effettivamente desiderato:

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

Quindi eseguire i passaggi dallo scenario A.

Scenario C : se ci fossero altre modifiche dal ramo o modifiche al master dopo l'unione che vuoi mantenere, sarebbe meglio ribasare il master e includere selettivamente i commit che desideri:

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

Nel tuo editor, rimuovi le righe che corrispondono ai commit che hanno aggiunto i file di grandi dimensioni, ma lascia tutto il resto così com'è. Salva ed esci. Il tuo ramo principale dovrebbe contenere solo ciò che desideri e nessun file di grandi dimensioni. Nota che git rebasesenza -peliminerà i commit di unione, quindi ti verrà lasciata una cronologia lineare per il master dopo <commit hash>. Questo probabilmente va bene per te, ma in caso contrario, potresti provare con -p, ma git help rebasedice combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

Quindi esegui i comandi dallo scenario A.


C'è una variante dello scenario A qui con, tuttavia, un problema inaspettato in più.

Scenario Un problema di miniera risolto, per eliminare una grande quantità di file di pacchetto temporaneo. Il repository è stato gestito da un server di compilazione e causa la creazione di file indesiderati all'interno della cartella .git / objects / pack. Potrei liberare GB preziosi dal mio disco.
xrissz

7

Come loganfsmyth ha già affermato nella sua risposta , è necessario eliminare la cronologia di git perché i file continuano a esistere lì anche dopo averli eliminati dal repository. I documenti ufficiali di GitHub consigliano BFG che trovo più facile da usare rispetto a filter-branch:

Eliminazione di file dalla cronologia

Scarica BFG dal loro sito web. Assicurati di aver installato java, quindi crea un clone di mirror ed elimina la cronologia. Assicurati di sostituire YOUR_FILE_NAMEcon il nome del file che desideri eliminare:

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

Elimina una cartella

Come sopra ma usa --delete-folders

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

Altre opzioni

BFG consente anche opzioni ancora più elaborate (vedi documenti ) come queste:

Rimuovi tutti i file più grandi di 100 M dalla cronologia:

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

Importante!

Quando esegui BFG, fai attenzione che entrambi YOUR_FILE_NAMEe in YOUR_FOLDER_NAMEeffetti siano solo nomi di file / cartelle. Non sono percorsi , quindi qualcosa di simile foo/bar.jpgnon funzionerà! Invece tutti i file / cartelle con il nome specificato verranno rimossi dalla cronologia del repository, indipendentemente dal percorso o dal ramo che esistevano.


Mi chiedo se voglio applicare questo bfgstrumento a un repository git locale, come dovrebbe apparire il comando?
Angel Todorov

5

Un'opzione:

eseguire git gcmanualmente per condensare un numero di file pack in uno o più file pack. Questa operazione è persistente (cioè il file di grandi dimensioni manterrà il suo comportamento di compressione) quindi potrebbe essere vantaggioso comprimere periodicamente un repository congit gc --aggressive

Un'altra opzione è salvare il codice e il .git da qualche parte, quindi eliminare il .git e ricominciare a utilizzare il codice esistente, creando un nuovo repository git ( git init).


Ciao Michael, ho provato a correre git gce sono passato a un paio di file pack ma quello grande è ancora uno di questi e vorrei solo sbarazzarmene in modo da poter eseguire il backup della cartella esternamente più facilmente (zip prima era 1 -2 Mb, ora 55 Mb). A meno che qualcuno non possa suggerire qualcos'altro, penso di dover creare un nuovo git. Presumo che questo significhi che perderò l'accesso ai rami che ho attualmente ecc ...?
user1116573

2
Ho smesso di provare e ho appena cancellato la cartella .git e ho creato un nuovo repository git come hai detto. La considererò una lezione appresa. Grazie Michael.
user1116573

4
Non ha molto senso. Perché non puoi semplicemente dire a git di consolidare il repository corrente e rimuovere i file del pacchetto nel processo?
jml

4

Esegui il seguente comando, sostituendo PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAcon il percorso del file che desideri rimuovere, non solo il nome del file. Questi argomenti:

  1. Forza Git a elaborare, ma non a estrarre, l'intera cronologia di ogni ramo e tag
  2. Rimuovi il file specificato, così come tutti i commit vuoti generati come risultato
  3. Sovrascrivi i tag esistenti
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

Ciò rimuoverà forzatamente tutti i riferimenti ai file dalla cronologia attiva del repository.

Passaggio successivo, eseguire un ciclo GC per forzare la scadenza e l'eliminazione di tutti i riferimenti al file dal file pack. Non è necessario sostituire nulla in questi comandi.

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

Finalmente dalla seconda parte ho ottenuto un repo da 28G fino a 158M. Quasi nient'altro su Google ha funzionato. Grazie.
Sridhar Sarnobat

Ho seguito i passaggi precedenti e ho eseguito il push come "git push origin --force --all" e tuttavia i miei rami remoti (master, sviluppo e funzionalità / ASD-1010) non sono stati puliti. Quando ho clonato di recente dal repository remoto, i file .pack erano ancora presenti. Come posso riflettere questa pulizia su tutti i rami git remoti ??
Sambit Swain

1

Sono un po 'in ritardo per lo spettacolo, ma nel caso in cui la risposta sopra non avesse risolto la domanda, ho trovato un altro modo. Rimuovi semplicemente il file di grandi dimensioni specifico da .pack. Ho riscontrato questo problema in cui ho archiviato accidentalmente un file di grandi dimensioni da 2 GB. Ho seguito i passaggi spiegati in questo link: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/


Dopo aver eseguito questo metodo, rimuoverà completamente l'intera cronologia del progetto o rimuoverà semplicemente il file specificato.
Samim Aftab Ahmed

-3

questa è una soluzione più pratica che di codifica. comprimi il file. Apri lo zip nel formato di visualizzazione file (diverso dallo decompressione). Elimina il file .pack. Decomprimere e sostituire la cartella. Funziona come un fascino!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.