J'ai un repo Git de 300 MB. Mes fichiers actuellement extraits pèsent 2 Mo et le dépôt git pèse 298 Mo. Il s’agit en principe d’un dépôt de code uniquement qui ne devrait pas peser plus de quelques Mo.
Très probablement, à un moment donné, quelqu'un a validé par accident des fichiers lourds (vidéo, images énormes, etc.), puis les a supprimés ... mais pas de git, nous avons donc une histoire avec des fichiers volumineux inutiles. Comment puis-je retrouver les gros fichiers dans l'historique git? Il y a plus de 400 commits, il est donc fastidieux d’en passer un par un.
NOTE: ma question ne concerne pas comment supprimer le fichier, mais comment trouver dans le première place.
J'ai déjà trouvé ce script très utile pour rechercher des objets volumineux (et non évidents) dans un référentiel git:
#!/bin/bash
#set -x
# Shows you the largest objects in your repo's pack file.
# Written for osx.
#
# @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/
# @author Antony Stubbs
# set the internal field separator to line break, so that we can iterate easily over the verify-pack output
IFS=$'\n';
# list all objects including their size, sort by size, take top 10
objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head`
echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file."
output="size,pack,SHA,location"
allObjects=`git rev-list --all --objects`
for y in $objects
do
# extract the size in bytes
size=$((`echo $y | cut -f 5 -d ' '`/1024))
# extract the compressed size in bytes
compressedSize=$((`echo $y | cut -f 6 -d ' '`/1024))
# extract the SHA
sha=`echo $y | cut -f 1 -d ' '`
# find the objects location in the repository tree
other=`echo "${allObjects}" | grep $sha`
#lineBreak=`echo -e "\n"`
output="${output}\n${size},${compressedSize},${other}"
done
echo -e $output | column -t -s ', '
Cela vous donnera le nom d'objet (SHA1sum) du blob, et vous pourrez alors utiliser un script comme celui-ci:
... pour trouver le commit qui pointe vers chacun de ces blobs.
Ce script shell affiche tous les objets blob du référentiel, classés du plus petit au plus grand.
Pour mon exemple de dépôt, il a fonctionné environ 100 fois plus vite que les autres trouvés ici.
Sur mon fidèle système Athlon II X4, il gère le référentiel du noyau Linux avec ses 5,6 millions d'objets dans un peu plus d'une minute.
git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| sed -n 's/^blob //p' \
| sort --numeric-sort --key=2 \
| cut -c 1-12,41- \
| $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Lorsque vous exécutez le code ci-dessus, vous obtiendrez une sortie lisible par un utilisateur Nice comme ceci:
...
0d99bb931299 530KiB path/to/some-image.jpg
2ba44098e28f 12MiB path/to/hires-image.png
bd1741ddce0d 63MiB path/to/some-video-1080p.mp4
utilisateurs macOS: étant donné que numfmt
n'est pas disponible sur macOS, vous pouvez omettre la dernière ligne et gérer les tailles brutes en octets ou brew install coreutils
.
Pour obtenir filtrage supplémentaire, insérez l'une des lignes suivantes avant la ligne sort
.
Pour exclure des fichiers présents dans HEAD
, insérez la ligne suivante:
| grep -vF --file=<(git ls-tree -r HEAD | awk '{print $3}') \
Pour afficher uniquement les fichiers dépassant la taille donnée (par exemple, 1MiB = 220B), insérez la ligne suivante:
| awk '$2 >= 2^20' \
Pour générer une sortie plus appropriée pour un traitement ultérieur par les ordinateurs, omettez les deux dernières lignes du script de base. Ils font tout le formatage. Cela vous laissera quelque chose comme ça:
...
0d99bb93129939b72069df14af0d0dbda7eb6dba 542455 path/to/some-image.jpg
2ba44098e28f8f66bac5e21210c2774085d2319b 12446815 path/to/hires-image.png
bd1741ddce0d07b72ccf69ed281e09bf8a2d0b2f 65183843 path/to/some-video-1080p.mp4
Pour la suppression du fichier, consultez cette question SO sur le sujet .
J'ai trouvé une solution one-liner sur page wiki du Département de physique de l'ETH Zurich (près de la fin de cette page). Il suffit de faire un git gc
pour supprimer les fichiers périmés, puis
git rev-list --objects --all \
| grep "$(git verify-pack -v .git/objects/pack/*.idx \
| sort -k 3 -n \
| tail -10 \
| awk '{print$1}')"
vous donnera les 10 plus gros fichiers du référentiel.
Il existe également une solution plus avancée, GitExtensions a maintenant un plugin qui le fait dans l’UI (et gère également les réécritures d’historique).
Étape 1 Ecrivez tous les fichiers SHA1 dans un fichier texte:
git rev-list --objects --all | sort -k 2 > allfileshas.txt
Step 2 Triez les blobs du plus grand au plus petit et écrivez les résultats dans un fichier texte:
git gc && git verify-pack -v .git/objects/pack/pack-*.idx | egrep "^\w+ blob\W+[0-9]+ [0-9]+ [0-9]+$" | sort -k 3 -n -r > bigobjects.txt
Étape 3a Combinez les deux fichiers texte pour obtenir des informations sur le nom de fichier/sha1/taille:
for SHA in `cut -f 1 -d\ < bigobjects.txt`; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | awk '{print $1,$3,$7}' >> bigtosmall.txt
done;
Étape 3b Si vous avez des noms de fichier ou des chemins contenant spaces, essayez cette variante de l'étape 3a. Il utilise cut
au lieu de awk
pour obtenir les colonnes souhaitées incl. espaces de la colonne 7 à la fin de la ligne:
for SHA in `cut -f 1 -d\ < bigobjects.txt`; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | cut -d ' ' -f'1,3,7-' >> bigtosmall.txt
done;
Maintenant, vous pouvez regarder le fichier bigtosmall.txt afin de décider quels fichiers vous voulez supprimer de votre historique Git.
Étape 4 Pour effectuer la suppression (notez que cette partie est lente car elle va examiner chaque commit dans votre historique pour rechercher des données sur le fichier que vous avez identifié):
git filter-branch --tree-filter 'rm -f myLargeFile.log' HEAD
La source
Les étapes 1 à 3a ont été copiées à partir de Recherche et purge de gros fichiers dans l'historique Git
MODIFIER
L'article a été supprimé au cours du second semestre de 2017, mais une copie archivée de celui-ci est toujours accessible à l'aide de/ Wayback Machine .
Vous devez utiliser BFG Repo-Cleaner .
Selon le site:
BFG est une alternative plus simple et plus rapide à git-filter-branch pour nettoyer les mauvaises données de l'historique de votre référentiel Git:
- Suppression de gros fichiers fous
- Suppression des mots de passe, informations d'identification et autres données privées
La procédure classique pour réduire la taille d'un référentiel serait:
git clone --mirror git://example.com/some-big-repo.git
Java -jar bfg.jar --strip-biggest-blobs 500 some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all
git gc --Prune=now --aggressive
git Push
Si vous voulez seulement avoir une liste de gros fichiers, alors j'aimerais vous fournir le one-liner suivant ( source chez renuo ):
join -o "1.1 1.2 2.3" <(git rev-list --objects --all | sort) <(git verify-pack -v objects/pack/*.idx | sort -k3 -n | tail -5 | sort) | sort -k3 -n
Dont la sortie sera:
commit file name size in bytes
72e1e6d20... db/players.sql 818314
ea20b964a... app/assets/images/background_final2.png 6739212
f8344b9b5... data_test/pg_xlog/000000010000000000000001 1625545
1ecc2395c... data_development/pg_xlog/000000010000000000000001 16777216
bc83d216d... app/assets/images/background_1forfinal.psd 95533848
La dernière entrée de la liste pointe vers le fichier le plus volumineux de votre historique git.
Vous pouvez utiliser cette sortie pour vous assurer que vous ne supprimez pas d'éléments avec BFG dont vous auriez eu besoin dans votre historique.
Si vous êtes sous Windows, voici un script PowerShell qui imprimera les 10 plus gros fichiers de votre référentiel:
$revision_objects = git rev-list --objects --all;
$files = $revision_objects.Split() | Where-Object {$_.Length -gt 0 -and $(Test-Path -Path $_ -PathType Leaf) };
$files | Get-Item -Force | select fullname, length | sort -Descending -Property Length | select -First 10
Essayez git ls-files | xargs du -hs --threshold=1M
.
Nous utilisons la commande ci-dessous dans notre pipeline CI. Elle s'arrête si des fichiers volumineux sont trouvés dans le référentiel git:
test $(git ls-files | xargs du -hs --threshold=1M 2>/dev/null | tee /dev/stderr | wc -l) -gt 0 && { echo; echo "Aborting due to big files in the git repository."; exit 1; } || true
Je suis tombé sur cela pour la même raison que quiconque. Mais les scripts cités ne fonctionnaient pas tout à fait pour moi. J'en ai créé un qui est plutôt un hybride de ceux que j'ai vus et il vit maintenant ici - https://gitlab.com/inorton/git-size-calc
Comment puis-je retrouver les gros fichiers dans l'historique git?
Commencez par analyser, valider et sélectionner la cause première. Utilisez git-repo-analysis
pour vous aider.
Vous pouvez également trouver une valeur dans les rapports détaillés générés par BFG Repo-Cleaner , qui peuvent être exécutés très rapidement en clonant dans un droplet Digital Ocean en utilisant leur débit réseau de 10 Mo/s.