No pude hacer uso de la respuesta más popular porque el --batch-check
cambio de línea de comandos a Git 1.8.3 (que tengo que usar) no acepta ningún argumento. Los pasos siguientes se han probado en CentOS 6.5 con Bash 4.1.2
Conceptos clave
En Git, el término blob implica el contenido de un archivo. Tenga en cuenta que una confirmación puede cambiar el contenido de un archivo o nombre de ruta. Por lo tanto, el mismo archivo podría referirse a un blob diferente dependiendo de la confirmación. Un determinado archivo podría ser el más grande en la jerarquía de directorios en un commit, mientras que no en otro. Por lo tanto, la cuestión de encontrar confirmaciones grandes en lugar de archivos grandes coloca los asuntos en la perspectiva correcta.
Para el impaciente
El comando para imprimir la lista de blobs en orden descendente de tamaño es:
git cat-file --batch-check < <(git rev-list --all --objects | \
awk '{print $1}') | grep blob | sort -n -r -k 3
Salida de muestra:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620
Para eliminar dichos blobs, use BFG Repo Cleaner , como se menciona en otras respuestas. Dado un archivo blobs.txt
que solo contiene los hash de blob, por ejemplo:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2
Hacer:
java -jar bfg.jar -bi blobs.txt <repo_dir>
La pregunta es sobre encontrar los commits, que es más trabajo que encontrar blobs. Para saber, sigue leyendo.
Más trabajo
Dado un hash de confirmación, un comando que imprime hash de todos los objetos asociados con él, incluidos los blobs, es:
git ls-tree -r --full-tree <commit_hash>
Entonces, si tenemos tales salidas disponibles para todos los commits en el repositorio, entonces dado un hash de blob, el montón de commits son los que coinciden con cualquiera de las salidas. Esta idea está codificada en el siguiente 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
Si los contenidos se guardan en un archivo llamado find-commits.sh
, una invocación típica será la siguiente:
cat blobs.txt | find-commits.sh
Como anteriormente, el archivo blobs.txt
enumera hash de blob, uno por línea. loscreate_db()
función guarda un caché de todos los listados de confirmación en un subdirectorio en el directorio actual.
Algunas estadísticas de mis experimentos en un sistema con dos procesadores Intel (R) Xeon (R) CPU E5-2620 2.00GHz presentados por el sistema operativo como 24 núcleos virtuales:
- Número total de confirmaciones en el repositorio = casi 11,000
- Velocidad de creación de archivos = 126 archivos / s. El script crea un solo archivo por confirmación. Esto ocurre solo cuando el caché se está creando por primera vez.
- Sobrecarga de creación de caché = 87 s.
- Velocidad de búsqueda promedio = 522 commits / s. La optimización de caché resultó en una reducción del 80% en el tiempo de ejecución.
Tenga en cuenta que el script tiene un solo subproceso. Por lo tanto, solo se usaría un núcleo a la vez.