Non sono stato in grado di utilizzare la risposta più popolare perché --batch-check
opzione da riga di comando su Git 1.8.3 (che devo usare) non accetta alcun argomento. I passaggi seguenti sono stati provati su CentOS 6.5 con Bash 4.1.2
Concetti chiave
In Git, il termine BLOB implica il contenuto di un file. Si noti che un commit potrebbe cambiare il contenuto di un file o percorso. Pertanto, lo stesso file potrebbe fare riferimento a un BLOB diverso a seconda del commit. Un certo file potrebbe essere il più grande nella gerarchia di directory in un commit, mentre non in un altro. Pertanto, la questione di trovare commit di grandi dimensioni anziché file di grandi dimensioni, pone le cose nella prospettiva corretta.
Per l'impaziente
Il comando per stampare l'elenco di BLOB in ordine decrescente di dimensioni è:
git cat-file --batch-check < <(git rev-list --all --objects | \
awk '{print $1}') | grep blob | sort -n -r -k 3
Uscita campione:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620
Per rimuovere tali BLOB, utilizzare BFG Repo Cleaner , come indicato in altre risposte. Dato un file blobs.txt
che contiene solo gli hash BLOB, ad esempio:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2
Fare:
java -jar bfg.jar -bi blobs.txt <repo_dir>
La domanda è su come trovare i commit, che è più lavoro che trovare blob. Per sapere, continua a leggere.
Ulteriori lavori
Dato un hash di commit, un comando che stampa gli hash di tutti gli oggetti ad esso associati, inclusi i BLOB, è:
git ls-tree -r --full-tree <commit_hash>
Quindi, se abbiamo tali output disponibili per tutti i commit nel repository, quindi dato un hash BLOB, il gruppo di commit è quello che corrisponde a uno qualsiasi degli output. Questa idea è codificata nel seguente script:
#!/bin/bash
DB_DIR='trees-db'
find_commit() {
cd ${DB_DIR}
for f in *; do
if grep -q $1 ${f}; then
echo ${f}
fi
done
cd - > /dev/null
}
create_db() {
local tfile='/tmp/commits.txt'
mkdir -p ${DB_DIR} && cd ${DB_DIR}
git rev-list --all > ${tfile}
while read commit_hash; do
if [[ ! -e ${commit_hash} ]]; then
git ls-tree -r --full-tree ${commit_hash} > ${commit_hash}
fi
done < ${tfile}
cd - > /dev/null
rm -f ${tfile}
}
create_db
while read id; do
find_commit ${id};
done
Se i contenuti vengono salvati in un file denominato, find-commits.sh
una chiamata tipica sarà come sotto:
cat blobs.txt | find-commits.sh
Come in precedenza, il file blobs.txt
elenca gli hash BLOB, uno per riga. Ilcreate_db()
funzione salva una cache di tutti gli elenchi di commit in una sottodirectory nella directory corrente.
Alcune statistiche dai miei esperimenti su un sistema con due processori Intel (R) Xeon (R) CPU E5-2620 a 2,00 GHz presentati dal sistema operativo come 24 core virtuali:
- Numero totale di commit nel repository = quasi 11.000
- Velocità di creazione del file = 126 file / s. Lo script crea un singolo file per commit. Ciò si verifica solo quando la cache viene creata per la prima volta.
- Overhead di creazione della cache = 87 s.
- Velocità di ricerca media = 522 commit / s. L'ottimizzazione della cache ha comportato una riduzione dell'80% del tempo di esecuzione.
Si noti che lo script è a thread singolo. Pertanto, verrà utilizzato un solo core alla volta.