it-swarm.com.de

Wie finde ich große Commits in der Git-Geschichte?

Ich habe ein Git Repo von 300 MB. Meine derzeit ausgecheckten Dateien wiegen 2 MB und das Git-Repo 298 MB. Dies ist im Grunde ein reiner Code, der nicht mehr als ein paar MB wiegen sollte.

Höchstwahrscheinlich hat jemand aus Versehen einige schwere Dateien (Videos, große Bilder usw.) begangen und sie dann entfernt ... aber nicht von git, also haben wir eine Geschichte mit nutzlosen großen Dateien. Wie kann ich die großen Dateien in der Git-Historie finden? Es gibt mehr als 400 Commits, daher ist es zeitaufwändig, eins nach dem anderen zu gehen. 

NOTE: Meine Frage geht nicht um wie entferne ich die Datei, sondern wie sie find in der erster Platz. 

243
user1305445

Ich habe dieses Skript in der Vergangenheit sehr nützlich gefunden, um große (und nicht offensichtliche) Objekte in einem Git-Repository zu finden:


#!/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 ', '

Das gibt Ihnen den Objektnamen (SHA1sum) des Blobs, und dann können Sie ein Skript wie dieses verwenden:

... um das Commit zu finden, das auf jeden dieser Blobs verweist.

107
Mark Longair

???? Ein unglaublich schneller Shell-Einliner ????

Dieses Shell-Skript zeigt alle Blob-Objekte im Repository an, sortiert nach kleinsten bis größten.

Für mein Beispiel-Repo lief es ungefähr 100-mal schneller als die anderen hier gefundenen.
Auf meinem zuverlässigen Athlon II X4-System verwaltet es das Linux Kernel-Repository mit seinen 5,6 Millionen Objekten in etwas mehr als einer Minute.

Das Basis-Skript

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

Wenn Sie den obigen Code ausführen, erhalten Sie Nice für Menschen lesbare Ausgabe wie folgt:

...
0d99bb931299  530KiB path/to/some-image.jpg
2ba44098e28f   12MiB path/to/hires-image.png
bd1741ddce0d   63MiB path/to/some-video-1080p.mp4

macOS-Benutzer: Da numfmt unter macOS nicht verfügbar ist, können Sie entweder die letzte Zeile weglassen und rohe Bytegrößen oder brew install coreutils verwenden.

Filterung

Um weitere Filterung zu erreichen, fügen Sie eine der folgenden Zeilen vor der sort-Zeile ein.

Um schließen Sie Dateien aus, die in HEAD vorhanden sind, fügen Sie die folgende Zeile ein:

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

An nur Dateien anzeigen, die die angegebene Größe überschreiten (z. B. 1MiB = 220B), füge folgende Zeile ein:

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

Ausgabe für Computer

Um eine Ausgabe zu erzeugen, die besser für die weitere Verarbeitung durch Computer geeignet ist, lassen Sie die letzten beiden Zeilen des Basisskripts weg. Sie machen alle Formatierungen. Dies wird dich mit so etwas verlassen:

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

Datei entfernen

Um die eigentliche Datei zu entfernen, checken Sie diese SO - Frage zum Thema aus.

338
raphinesse

Ich habe auf der Wiki-Seite ETH Zürich Departement für Physik eine Ein-Liner-Lösung gefunden (am Ende dieser Seite). Führen Sie einfach einen git gc aus, um veralteten Müll zu entfernen, und dann

git rev-list --objects --all \
  | grep "$(git verify-pack -v .git/objects/pack/*.idx \
           | sort -k 3 -n \
           | tail -10 \
           | awk '{print$1}')"

gibt Ihnen die 10 größten Dateien im Repository.

Es gibt jetzt auch eine faulere Lösung. GitExtensions verfügt jetzt über ein Plugin, das dies in der Benutzeroberfläche ausführt (und auch Historienumschreibungen behandelt).

GitExtensions 'Find large files' dialog

149
skolima

Schritt 1 Alle SHA1-Dateien in eine Textdatei schreiben:

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

Schritt 2 Sortieren Sie die Blobs vom größten zum kleinsten und schreiben Sie die Ergebnisse in eine Textdatei:

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

Schritt 3a Kombinieren Sie beide Textdateien, um den Dateinamen/sha1/size zu erhalten:

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;

Schritt 3b Wenn Sie Dateinamen oder Pfadnamen mit Leerzeichen haben, versuchen Sie diese Variante von Schritt 3a. Es verwendet cut anstelle von awk, um die gewünschten Spalten inkl. Leerzeichen von Spalte 7 bis zum Zeilenende:

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;

Nun können Sie sich die Datei bigtosmall.txt ansehen, um zu entscheiden, welche Dateien Sie aus Ihrem Git-Verlauf entfernen möchten.

Schritt 4 So führen Sie das Entfernen durch (beachten Sie, dass dieser Teil langsam ist, da er jedes Commit in Ihrem Protokoll auf Daten über die von Ihnen identifizierte Datei überprüft):

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

Quelle

Die Schritte 1-3a wurden kopiert aus Suchen und Löschen großer Dateien aus dem Git-Verlauf

EDIT

Der Artikel wurde irgendwann im zweiten Halbjahr 2017 gelöscht, aber eine archivierte Kopie davon kann weiterhin mit der Wayback Machine aufgerufen werden.

24
friederbluemle

Sie sollten BFG Repo-Cleaner verwenden.

Laut der Website:

Das BFG ist eine einfachere, schnellere Alternative zu git-filter-branch für bereinigen Sie schlechte Daten aus Ihrem Git-Repository-Verlauf:

  • Verrückte große Dateien entfernen
  • Entfernen von Passwörtern, Anmeldeinformationen und anderen privaten Daten

Das klassische Verfahren zur Reduzierung der Größe eines Repositorys wäre:

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

Wenn Sie nur eine Liste großer Dateien haben möchten, möchte ich Ihnen den folgenden Einzeiler ( source at renuo ) zur Verfügung stellen:

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

Dessen Ausgabe wird sein:

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

Der letzte Eintrag in der Liste zeigt auf die größte Datei in Ihrem Git-Verlauf.

Sie können diese Ausgabe verwenden, um sicherzustellen, dass Sie keine Daten mit BFG löschen, die Sie in Ihrem Verlauf benötigt hätten.

8
schmijos

Wenn Sie mit Windows arbeiten, finden Sie hier ein PowerShell-Skript, mit dem die 10 größten Dateien in Ihrem Repository gedruckt werden:

$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

Versuchen Sie git ls-files | xargs du -hs --threshold=1M.

Wir verwenden den folgenden Befehl in unserer CI-Pipeline. Er hält an, wenn er große Dateien im git repo findet:

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

Ich stolperte aus demselben Grund wie jeder andere darüber. Aber die zitierten Skripte haben für mich nicht ganz funktioniert. Ich habe einen gemacht, der eher eine Mischung aus denen ist, die ich gesehen habe, und er lebt jetzt hier - https://gitlab.com/inorton/git-size-calc

0
IanNorton

Wie kann ich die großen Dateien in der Git-Historie finden?

Beginnen Sie mit der Analyse, Validierung und Auswahl der Hauptursache. Verwenden Sie git-repo-analysis , um zu helfen.

Möglicherweise finden Sie auch in den von BFG Repo-Cleaner generierten detailreports einen Wert, die sehr schnell ausgeführt werden können, indem Sie mit einem 10-MBit/s-Netzwerkdurchsatz auf ein Digital Ocean-Droplet klonen.

0
Josh Habdas