Comment trouver / identifier des fichiers volumineux/commits dans l'historique Git?

J'ai un dépôt git de 300 Mo. Mes fichiers actuellement extraits pèsent 2 Mo, et le repo git pèse 298 Mo. Il s'agit essentiellement d'un repo code uniquement qui ne devrait pas peser plus de quelques Mo.

Très probablement, quelqu'un à un moment donné a commis des fichiers lourds par accident (vidéo, images énormes, etc.), puis les a supprimés...mais pas de git, donc nous avons une histoire avec des fichiers volumineux inutiles. Comment puis-je retrouver les gros fichiers de l'historique git? Il y a 400 + commits, donc aller Un Par sera de temps.

NOTE: ma question n'est pas à propos de comment faire pour supprimer le fichier, mais comment trouver c'est en premier lieu.

210
git
demandé sur Community 2012-05-16 19:54:14

9 réponses

J'ai trouvé ce script très utile dans le passé pour trouver des objets volumineux (et non évidents) dans un dépôt 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 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'objet (SHA1sum) du blob, et vous pourrez alors utiliser un script comme celui-ci:

... pour trouver le commit qui pointe pour chacune de ces gouttes.

95
répondu Mark Longair 2017-05-23 11:55:07

Une doublure en coque extrêmement rapide

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

Pour mon exemple de repo, il a couru environ 100 fois plus vite {[15] } que les autres trouvés ici.
Sur mon fidèle système Athlon II X4, il gère le dépôt du noyau Linux avec ses 5,6 millions d'objets dans 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 nice 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 : puisque numfmt n'est pas disponible sur macOS, vous pouvez soit brew install coreutils --with-default-names ou simplement omettre la dernière ligne et traiter les tailles d'octets bruts à la place.

Filtrage

Pour obtenir d'autres filtrage, insérez l'une des lignes suivantes avant sort ligne.

Pour exclure les fichiers présents dans HEAD, insérer la ligne suivante:

| grep -vF --file=<(git ls-tree -r HEAD | awk '{print $3}') \

À afficher seuls les fichiers dépassant la taille donnée (par exemple 1 MiB = 220 B), insérer la ligne suivante:

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

Sortie pour Ordinateurs

Pour générer une sortie qui est 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 avec 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 réelle du fichier, consultez cette question SO sur le sujet.

250
répondu raphinesse 2018-08-03 23:29:17

J'ai trouvé une solution unique sur la 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 déchets 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 fichiers les plus volumineux du référentiel.

Il y a aussi une solution lazier 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 "Rechercher des fichiers volumineux" de GitExtensions

146
répondu skolima 2016-06-10 15:18:33

Étape 1 Ecrire tous les fichiers SHA1s 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 des informations sur le nom du 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 fichiers ou de noms de chemin d'accès contenant espaces essayez cette variante de l'Étape 3a. Il utilise cut au lieu de awk pour obtenir les colonnes incl. espaces de la colonne 7 à la fin de 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 souhaitez supprimer de votre historique Git.

Étape 4 pour effectuer la suppression (notez que cette partie est lente car elle va examiner chaque validation de votre historique pour les données sur le fichier que vous avez identifié):

git filter-branch --tree-filter 'rm -f myLargeFile.log' HEAD

Source

Les étapes 1-3a ont été copiées à partir de recherche et purge de gros fichiers de Git Histoire

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 en utilisant la machine Wayback.

24
répondu friederbluemle 2017-10-04 17:36:18

Vous devez utiliser BFG Repo-Nettoyant.

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 dépôt 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
21
répondu Warren Seine 2015-01-16 20:42:09

Si vous souhaitez seulement avoir une liste de fichiers volumineux, alors je voudrais vous fournir le one-liner suivant (source à 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 plus grand fichier de votre historique git.

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

8
répondu schmijos 2016-11-16 08:32:17

Si vous êtes sous Windows, voici un script PowerShell qui imprimera 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
2
répondu Julia Schwarz 2016-05-14 23:19:04

Comment puis-je retrouver les gros fichiers de l'historique git?

Commencez par analyser, valider et sélectionner la cause première. Utilisation git-repo-analysis pour les 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 sur une goutte D'océan numérique en utilisant leur débit réseau 10MiB / S.

0
répondu Josh Habdas 2017-05-26 13:13:48

Je suis tombé sur ceci pour la même raison que n'importe qui d'autre. Mais les scripts Cités n'ont pas tout à fait fonctionné pour moi. J'en ai fait un qui est plus un hybride de ceux que j'ai vus et il vit maintenant ici - https://gitlab.com/inorton/git-size-calc

0
répondu IanNorton 2018-01-25 22:03:06