web-dev-qa-db-fra.com

Comment trouver/identifier les gros commits dans l'histoire de git?

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. 

243
user1305445

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.

107
Mark Longair

???? Un one-liner Shell ultra-rapide ????

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.

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- \
| $(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.

Filtration

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' \

Sortie pour ordinateurs

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

Suppression de fichier

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

338
raphinesse

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).

GitExtensions 'Find large files' dialog

149
skolima

É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 .

24
friederbluemle

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
23
Warren Seine

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.

8
schmijos

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
3
Julia Schwarz

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
1
Vojtech Vitek

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

0
IanNorton

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.

0
Josh Habdas