Comment trouver / identifier de gros fichiers / commits dans l’historique de Git?

J’ai un repository git de 300 Mo. Mes fichiers actuellement extraits pèsent 2 Mo et le repository git pèse 298 Mo. Ceci est fondamentalement un repo de code seulement qui ne devrait pas peser plus que quelques MB.

Très probablement, quelqu’un à un moment donné a commis des fichiers lourds par accident (vidéo, images volumineuses, etc.), puis les a supprimées … mais pas de git, nous avons donc un historique avec des fichiers volumineux inutiles. Comment puis-je retrouver les gros fichiers de l’histoire de git? Il y a plus de 400 commits, donc passer un par un prendra beaucoup de temps.

REMARQUE : ma question n’est pas de savoir comment supprimer le fichier , mais comment le trouver en premier lieu.

J’ai trouvé ce script très utile dans le passé pour trouver des objects volumineux (et non évidents) dans un repository 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-sortingm-your-waist-line/ # @author Antony Stubbs # set the internal field spereator 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’object (SHA1sum) du blob, et vous pourrez alors utiliser un script comme celui-ci:

  • Quel commit a ce blob?

… pour trouver le commit qui pointe vers chacun de ces blobs.

🚀 Une shell extrêmement rapide shell

Ce script shell affiche tous les objects blob du référentiel, sortingés du plus petit au plus grand.

Pour mon exemple de repo, 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 kernel Linux avec ses 5,6 millions d’objects en un peu plus d’une minute .

Le script de base

 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- \ | numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest 

Lorsque vous exécutez le code ci-dessus, vous obtiendrez une belle sortie lisible par l’homme, 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 Mac : comme numfmt n’est pas disponible sur macOS, vous pouvez soit brew install coreutils --with-default-names soit simplement omettre la dernière ligne et traiter à la place les tailles d’octets brutes.

Filtration

Pour obtenir un filtrage supplémentaire , insérez l’une des lignes suivantes avant la ligne de sort .

Pour exclure les 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 une taille donnée (par exemple 1 Mio = 2 20 B), insérez la ligne suivante:

 | awk '$2 >= 2^20' \ 

Sortie pour ordinateurs

Pour générer une sortie plus adaptée au 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 ceci:

 ... 0d99bb93129939b72069df14af0d0dbda7eb6dba 542455 path/to/some-image.jpg 2ba44098e28f8f66bac5e21210c2774085d2319b 12446815 path/to/hires-image.png bd1741ddce0d07b72ccf69ed281e09bf8a2d0b2f 65183843 path/to/some-video-1080p.mp4 

Suppression de fichier

Pour la suppression effective du fichier, consultez cette question SO sur le sujet .

J’ai trouvé une solution à un trait sur la page wiki du département de physique de l’ETH Zurich (à la fin de cette page). Il suffit de faire un git gc pour supprimer les données inutiles, 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 y a aussi une solution plus paresseuse maintenant disponible, GitExtensions a maintenant un plugin qui le fait dans l’interface utilisateur (et gère également les réécritures de l’historique).

Boîte de dialogue GitExtensions 'Rechercher des fichiers volumineux'

Étape 1 Écrivez tous les fichiers SHA1 dans un fichier texte:

 git rev-list --objects --all | sort -k 2 > allfileshas.txt 

Étape 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 le nom du fichier / les informations sha1 / size:

 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 fichiers ou des noms de chemins contenant des espaces, essayez cette variante de l’étape 3a. Il utilise la 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 examinera chaque validation de votre historique pour obtenir 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 à 3 a été copiées à partir de la recherche et de la purge de gros fichiers de l’historique de Git

MODIFIER

L’article a été supprimé au cours de la seconde moitié 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:

Le BFG est une alternative plus simple et plus rapide à git-filter-branch pour nettoyer les mauvaises données de l’historique de votre repository Git:

  • Suppression de fichiers Big Crazy
  • Suppression des mots de passe, informations d’identification et autres données privées

La procédure classique de réduction de la taille d’un référentiel serait la suivante:

 git clone --mirror git://example.com/some-big-repo.git java -jar bfg.jar --ssortingp-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 je voudrais 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 le résultat 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 plus grand fichier de votre historique.

Vous pouvez utiliser cette sortie pour vous assurer que vous ne supprimez pas des éléments avec BFG dont vous auriez besoin dans votre historique.

Si vous êtes sous Windows, voici un script PowerShell qui imprime les 10 fichiers les plus volumineux 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 

Comment puis-je retrouver les gros fichiers de l’histoire de git?

Commencez par parsingr, valider et sélectionner la cause première. Utilisez git-repo-analysis pour vous aider.

Vous pouvez également trouver une certaine 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 vers une gouttelette Digital Ocean en utilisant leur débit réseau de 10MiB / s.

Je suis tombé sur cela pour la même raison que quiconque. Mais les scripts cités n’ont pas vraiment fonctionné pour moi. J’en ai fabriqué un qui est plus un hybride de ceux que j’ai vu et il vit maintenant ici – https://gitlab.com/inorton/git-size-calc