Je n'ai pas pu utiliser la réponse la plus populaire car le --batch-check
commutateur de ligne de commande vers Git 1.8.3 (que je dois utiliser) n'accepte aucun argument. Les étapes suivantes ont été essayées sur CentOS 6.5 avec Bash 4.1.2
Concepts clés
Dans Git, le terme blob implique le contenu d'un fichier. Notez qu'un commit peut changer le contenu d'un fichier ou d'un nom de chemin. Ainsi, le même fichier peut faire référence à un autre blob en fonction de la validation. Un certain fichier peut être le plus gros de la hiérarchie de répertoires dans un commit, mais pas dans un autre. Par conséquent, la question de trouver des commits volumineux au lieu de fichiers volumineux met les choses dans la bonne perspective.
Pour les impatients
La commande pour imprimer la liste des blobs dans l'ordre décroissant de taille est:
git cat-file --batch-check < <(git rev-list --all --objects | \
awk '{print $1}') | grep blob | sort -n -r -k 3
Exemple de sortie:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620
Pour supprimer de tels blobs, utilisez le BFG Repo Cleaner , comme mentionné dans d'autres réponses. Étant donné un fichier blobs.txt
qui contient uniquement les hachages de blob, par exemple:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2
Faire:
java -jar bfg.jar -bi blobs.txt <repo_dir>
La question est de trouver les commits, ce qui est plus de travail que de trouver des blobs. Pour le savoir, lisez la suite.
La poursuite des travaux
Étant donné un hachage de validation, une commande qui affiche les hachages de tous les objets qui lui sont associés, y compris les blobs, est:
git ls-tree -r --full-tree <commit_hash>
Donc, si nous avons de telles sorties disponibles pour toutes les validations dans le référentiel, étant donné un hachage de blob, le groupe de validations sont celles qui correspondent à l'une des sorties. Cette idée est encodée dans le script suivant:
#!/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
Si le contenu est enregistré dans un fichier nommé find-commits.sh
alors une invocation typique sera comme sous:
cat blobs.txt | find-commits.sh
Comme précédemment, le fichier blobs.txt
répertorie les hachages d'objets blob, un par ligne. La create_db()
fonction enregistre un cache de toutes les listes de commit dans un sous-répertoire du répertoire courant.
Quelques statistiques de mes expériences sur un système avec deux processeurs Intel (R) Xeon (R) CPU E5-2620 2.00GHz présentés par l'OS comme 24 cœurs virtuels:
- Nombre total de commits dans le repo = près de 11 000
- Vitesse de création de fichiers = 126 fichiers / s. Le script crée un seul fichier par commit. Cela se produit uniquement lorsque le cache est créé pour la première fois.
- Surcharge de création de cache = 87 s.
- Vitesse de recherche moyenne = 522 commits / s. L'optimisation du cache a entraîné une réduction de 80% du temps d'exécution.
Notez que le script est monothread. Par conséquent, un seul cœur serait utilisé à la fois.