Pour trouver les plus gros fichiers stockés dans l’historique Git accessible d’un dépôt sur macOS, ouvrez le Terminal, placez-vous dans le dépôt et redirigez la liste des objets Git vers git cat-file et sort. Cela indique la taille non compressée de chaque blob en octets ainsi qu'une indication de chemin. Cela permet de révéler des fichiers qui ont été supprimés ou remplacés mais qui subsistent dans des commits accessibles depuis des branches ou des tags.

Lancer une analyse de l’historique depuis le Terminal

Dans le Terminal, utilisez cd pour entrer dans le dépôt. Mettez le chemin du dossier entre guillemets s'il contient des espaces. Exécutez ensuite :

git rev-list --objects --all |
  git cat-file --batch-check='%(objecttype) %(objectsize) %(objectname) %(rest)' |
  awk '$1 == "blob"' |
  sort -k2,2nr |
  head -20

La sortie est triée du plus grand au plus petit. Chaque ligne affiche le type d'objet, le nombre d'octets, l'identifiant de l'objet et, lorsque Git en fournit un, une indication de chemin. git rev-list --objects --all parcourt les objets référencés par les commits accessibles depuis les références, comme les branches locales et les tags ; git cat-file --batch-check indique le type et la taille de chaque objet. Le pipeline filtre pour ne conserver que les blobs, les objets qui contiennent le contenu des fichiers. La documentation de rev-list de Git décrit le parcours et les noms des objets, et cat-file documente la sortie de la taille et du type en mode batch.

sort -k2,2nr utilise la commande intégrée sort de macOS pour trier numériquement dans l'ordre décroissant selon le deuxième champ séparé par des espaces, à savoir la taille en octets. head -20 limite l'affichage à 20 lignes ; modifiez ce nombre ou supprimez cette dernière ligne pour en voir davantage. La commande lit uniquement les données du dépôt. Elle ne modifie ni les commits ni les fichiers.

Interpréter les résultats avec précaution

Une ligne identifie un objet blob, et non nécessairement un fichier actuellement présent dans l'arbre de travail (working tree). Un objet volumineux peut provenir d'une ancienne version d'un fichier, et une indication de chemin ne constitue pas un index complet de l'historique des chemins : Git précise qu'avec --objects, les noms ne sont que des indications, peuvent être modifiés pour les sauts de ligne, et lorsqu'un objet possède plusieurs noms, un seul peut être affiché. Considérez le chemin affiché comme une piste, puis examinez les commits concernés pour vérifier quand et où le contenu est apparu. Les notes sur les noms d'objets de rev-list expliquent ces limitations.

Cette analyse couvre les objets accessibles depuis les références découvertes par --all, et non l'intégralité des objets qui pourraient être physiquement conservés dans la base de données d'objets. Pour inspecter le stockage local des objets, y compris les objets inaccessibles, exécutez :

git cat-file --batch-all-objects \
  --batch-check='%(objecttype) %(objectsize) %(objectname)' |
  awk '$1 == "blob"' |
  sort -k2,2nr |
  head -20

--batch-all-objects parcourt tous les objets du dépôt et des magasins d'objets alternatifs, y compris les objets qui ne sont pas accessibles depuis des références. Cette seconde commande omet les chemins de fichiers ; utilisez donc l'identifiant de l'objet pour poursuivre vos investigations. La documentation de cat-file note à la fois cette couverture d'objets plus large et le fait que chaque objet n'est affiché qu'une seule fois, même s'il est stocké plusieurs fois.

La taille d'un blob n'est pas équivalente à l'espace disque

La valeur rapportée pour objectsize correspond à la taille non compressée d'un objet Git. Git peut compresser les objets ou les stocker sous forme de deltas dans des fichiers pack (packfiles), de sorte qu'un gros blob ne consomme pas nécessairement cette quantité exacte d'espace disque. Pour obtenir un aperçu de l'utilisation du stockage, exécutez git count-objects -vH ; son champ size-pack indique la taille des données empaquetées et ses autres champs résument les objets libres (loose objects) et le stockage associé. Le manuel de count-objects de Git documente ces valeurs. Pour inspecter la taille des objets empaquetés et les détails des deltas, git verify-pack -v liste la taille de chaque objet empaqueté ainsi que sa taille dans le packfile, mais nécessite le fichier .idx correspondant. Le manuel de verify-pack définit cette sortie.

Si vous trouvez un gros fichier dans l'historique

Déterminez d'abord si votre objectif est de comprendre l'état de l'extraction actuelle ou de réduire l'historique du dépôt. Pour la seule version actuelle, examinez les fichiers dans le Finder ou utilisez une liste des tailles de fichiers dans le Terminal ; l'analyse de l'historique répond à une question différente en recherchant les objets Git accessibles.

Si un fichier volumineux doit être supprimé de chaque révision, le supprimer simplement dans un nouveau commit n'efface pas les anciennes copies de l'historique. La réécriture de l'historique modifie les identifiants de commit et affecte les autres personnes utilisant le dépôt ; coordonnez-vous donc avant de procéder et conservez une sauvegarde. Le projet git-filter-repo propose un mode d'analyse en lecture seule, git filter-repo --analyze, qui génère des rapports pour vous aider à décider ce qu'il convient de filtrer ; il n'effectue aucune réécriture en mode analyse. La documentation du projet décrit cette option d'analyse et rappelle que le filtrage réécrit l'historique.

Le premier pipeline constitue le point de départ idéal lorsque l'objectif est de trouver les contenus de fichiers les plus volumineux au sein de l'historique d'un dépôt local. Utilisez l'analyse de tous les objets lorsque les résidus inaccessibles ont une importance, et comparez les tailles des objets Git avec le stockage des packs avant d'attribuer la consommation d'espace disque à un blob en particulier.

Sources