2012-04-09 16 views
168

Stavo lavorando su un repository sul mio account GitHub e questo è un problema su cui mi sono imbattuto. progettoRimuovi la cartella e il suo contenuto da git/cronologia di GitHub

  • Node.js con una cartella con alcuni pacchetti NPM installati
  • I pacchetti erano in node_modules cartella
  • Aggiunto quella cartella a git repository e ha spinto il codice per github (non è stato pensare al npm parte a quel tempo)
  • sono reso conto che non si ha realmente bisogno di quella cartella per essere una parte del codice
  • eliminata quella cartella, spinto

In questo caso, la dimensione del repository git totale era intorno a 6MB dove il codice effettivo (tutti tranne quella cartella) era solo intorno a 300 KB.

Ora quello che sto cercando alla fine è un modo per sbarazzarsi dei dettagli di quella cartella del pacchetto dalla cronologia di git, quindi se qualcuno lo clona, ​​non è necessario scaricare 6 MB di valore della cronologia in cui gli unici file effettivi riceveranno fin dall'ultimo commit sarebbero 300KB.

ho cercato soluzioni possibili per questo e provato questi 2 metodi

Il Gist sembrava ha funzionato dove, dopo l'esecuzione dello script, è ha mostrato che si è sbarazzato di quella cartella e in seguito ha mostrato che sono stati modificati 50 diversi commit. Ma non mi ha permesso di spingere quel codice. Quando ho provato a spingerlo, ha detto Branch up to date ma ha mostrato che 50 commit sono stati modificati su un git status. Anche gli altri 2 metodi non sono stati d'aiuto.

Ora, anche se ha dimostrato che si è sbarazzato della cronologia di quella cartella, quando ho controllato la dimensione di quel repository sul mio localhost, era ancora intorno ai 6 MB. (Ho anche eliminato la cartella refs/original ma non ho visto la modifica della dimensione del repository).

Quello che sto cercando di chiarire è, se c'è un modo per sbarazzarsi non solo della cronologia del commit (che è l'unica cosa che penso sia accaduta) ma anche di quei file git sta tenendo presumendo che uno voglia di rollback.

permette di dire una soluzione si presenta per questo e viene applicato sul mio localhost ma cant essere riprodotto a quella GitHub pronti contro termine, è possibile clonare che repo, rollback al primo commit eseguire il trucco e spingerlo (o fa che significa che git avrà ancora una storia di tutti questi commit? - alias. 6MB).

Il mio obiettivo finale qui è fondamentalmente trovare il modo migliore per sbarazzarsi del contenuto della cartella da git in modo che un utente non debba scaricare 6 MB di roba e ancora possibilmente avere gli altri commit che non hanno mai toccato i moduli cartella (che è più o meno tutti) nella storia di git.

Come posso fare questo?

+0

Se una delle risposte di seguito ha risolto il problema, forse dovresti considerare di accettarne una come risposta alla tua domanda. https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – starbeamrainbowlabs

risposta

320

Se siete qui per copiare-incollare il codice:

Questo è un esempio che rimuove node_modules dalla storia

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD 
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 
echo node_modules/ >> .gitignore 
git add .gitignore 
git commit -m 'Removing node_modules from git history' 
git gc 
git push origin master --force 
+13

Ho dovuto anche eseguire 'git gc' dopo aver eseguito i comandi per liberare tutto lo spazio utilizzato dai riferimenti rimossi . – pagliuca

+12

Vale la pena notare che se è necessario spingere questo upstream, probabilmente sarà necessario forzare un aggiornamento non fast forward usando 'git push origin master --force' – DaveStephens

+10

Questa dovrebbe essere la risposta accettata! – prakharsingh95

5

copia completa & incolla ricetta, semplicemente aggiungendo i comandi nei commenti (per la soluzione di copia-incolla), dopo di loro il test:

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD 
echo node_modules/ >> .gitignore 
git add .gitignore 
git commit -m 'Removing node_modules from git history' 
git gc 
git push origin master --force 

dopo questo, è possibile rimuovere le "node_modules /" linea da .gitignor e

106

Trovo che l'opzione --tree-filter utilizzata in altre risposte possa essere molto lenta, specialmente su repository di grandi dimensioni con molti commit.

Ecco il metodo che uso per rimuovere completamente una directory dalla storia git utilizzando l'opzione --index-filter, che corre molto più veloce:

# Make a fresh clone of YOUR_REPO 
git clone YOUR_REPO 
cd YOUR_REPO 

# Create tracking branches of all branches 
for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done 

# Remove DIRECTORY_NAME from all commits, then remove the refs to the old commits 
# (repeat these two commands for as many directories that you want to remove) 
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch DIRECTORY_NAME/' --prune-empty --tag-name-filter cat -- --all 
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 

# Ensure all old refs are fully removed 
rm -Rf .git/logs .git/refs/original 

# Perform a garbage collection to remove commits with no refs 
git gc --prune=all --aggressive 

# Force push all branches to overwrite their history 
# (use with caution!) 
git push origin --all --force 
git push origin --tags --force 

È possibile controllare la dimensione del repository prima e dopo il gc con :

git count-objects -vH 
+2

potresti spiegare perché questo è molto più veloce? – knocte

+6

@knocte: dai documenti (https://git-scm.com/docs/git-filter-branch). "--index-filter: ... è simile al filtro ad albero ma non controlla l'albero, il che lo rende molto più veloce" –

+9

Perché questa non è la risposta accettata? È così completo. –

18

Oltre alla risposta popolare above vorrei aggiungere alcune note per di Windows -Systems. Il comando

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD 
  • opere perfettamente senza alcuna modifica! Pertanto, non è necessario utilizzare Remove-Item, del o qualsiasi altra cosa invece di rm -rf.

  • Se è necessario specificare il percorso di un file o una directory uso barre come ./path/to/node_modules

+1

È il comando perfetto e più semplice anche su Linux. – peterh

+0

Questo non funzionerà su Windows se la directory contiene a. (punto) nel nome. –

+2

E ho trovato la soluzione. Utilizzare le doppie virgolette per il comando rm in questo modo: "rm -rf node.modules". –

7

Il metodo migliore e più accurato che ho trovato è stato quello di scaricare il file bfg.jar: https://rtyley.github.io/bfg-repo-cleaner/

Poi eseguire i comandi:

git clone --bare https://project/repository project-repository 
cd project-repository 
java -jar bfg.jar --delete-folders node_modules 
git reflog expire --expire=now --all && git gc --prune=now --aggressive 
git push --mirror https://project/new-repository 

Se si desidera eliminare i file quindi utilizzare l'opzione Cancella i file invece:

java -jar bfg.jar --delete-files *.pyc 
+1

molto facile :) se vuoi fare in modo che solo una cartella specifica venga rimossa, questo aiuterà: https://stackoverflow.com/questions/21142986/remove-filenames-from-specific-path – emjay

0

ho rimosso il bin e obj cartelle da vecchi progetti C# utilizzando git su Windows. Fate attenzione con

git filter-branch --tree-filter "rm -rf bin" --prune-empty HEAD 

Distrugge l'integrità dell'installazione git eliminando la cartella usr/bin nella git cartella di installazione.