Ich konnte die beliebteste Antwort nicht verwenden, weil die --batch-check
Befehlszeilenwechsel zu Git 1.8.3 (den ich verwenden muss) akzeptiert keine Argumente. Die folgenden Schritte wurden auf CentOS 6.5 mit Bash 4.1.2 ausprobiert
Wichtige Konzepte
In Git wird der Begriff Klecks impliziert den Inhalt einer Datei. Beachten Sie, dass eine Übertragung den Inhalt einer Datei oder eines Pfadnamens ändern kann. So kann dieselbe Datei je nach Commit auf einen anderen Blob verweisen. Eine bestimmte Datei kann in einem Commit die größte in der Verzeichnishierarchie sein, in einem anderen aber nicht. Die Frage nach großen Commits anstelle von großen Dateien rückt daher die Dinge in die richtige Perspektive.
Für die Ungeduldigen
Der Befehl zum Drucken der Liste der Blobs in absteigender Reihenfolge der Größe lautet:
git cat-file --batch-check < <(git rev-list --all --objects | \
awk '{print $1}') | grep blob | sort -n -r -k 3
Beispielhafte Ausgabe:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620
Um solche Blobs zu entfernen, verwenden Sie die BFG Repo-Reiniger wie in anderen Antworten erwähnt. Gegeben eine Datei blobs.txt
die z. B. nur die Hashes der Blobs enthält:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2
Machen:
java -jar bfg.jar -bi blobs.txt <repo_dir>
Die Frage bezieht sich auf das Auffinden der Commits, was mehr Arbeit bedeutet als das Auffinden von Blobs. Um das zu wissen, lesen Sie bitte weiter.
Weitere Arbeiten
Bei einem Commit-Hash ist ein Befehl, der Hashes aller mit ihm verbundenen Objekte, einschließlich Blobs, ausgibt:
git ls-tree -r --full-tree <commit_hash>
Wenn wir also solche Ausgaben für alle Commits im Repo zur Verfügung haben, dann sind bei einem Blob-Hash die Commits, die mit einer der Ausgaben übereinstimmen, der Bunch. Diese Idee ist in dem folgenden Skript kodiert:
#!/bin/bash
DB_DIR='trees-db'
find_commit() {
cd ${DB_DIR}
for f in *; do
if grep -q $1 ${f}; then
echo ${f}
fi
done
cd - > /dev/null
}
create_db() {
local tfile='/tmp/commits.txt'
mkdir -p ${DB_DIR} && cd ${DB_DIR}
git rev-list --all > ${tfile}
while read commit_hash; do
if [[ ! -e ${commit_hash} ]]; then
git ls-tree -r --full-tree ${commit_hash} > ${commit_hash}
fi
done < ${tfile}
cd - > /dev/null
rm -f ${tfile}
}
create_db
while read id; do
find_commit ${id};
done
Wenn der Inhalt in einer Datei mit dem Namen find-commits.sh
dann wird ein typischer Aufruf wie folgt aussehen:
cat blobs.txt | find-commits.sh
Wie bereits zuvor, wird die Datei blobs.txt
listet Blob-Hashes auf, einen pro Zeile. Die create_db()
speichert einen Zwischenspeicher für alle Commit-Listen in einem Unterverzeichnis des aktuellen Verzeichnisses.
Einige Statistiken aus meinen Experimenten auf einem System mit zwei Intel(R) Xeon(R) CPU E5-2620 2.00GHz Prozessoren, die vom Betriebssystem als 24 virtuelle Kerne dargestellt werden:
- Gesamtzahl der Übertragungen im Repo = fast 11.000
- Geschwindigkeit der Dateierstellung = 126 Dateien/s. Das Skript erstellt eine einzige Datei pro Übertragung. Dies geschieht nur, wenn der Cache zum ersten Mal erstellt wird.
- Aufwand für die Cache-Erstellung = 87 s.
- Durchschnittliche Suchgeschwindigkeit = 522 Übertragungen/s. Die Cache-Optimierung führte zu einer Reduzierung der Laufzeit um 80 %.
Beachten Sie, dass das Skript einen einzigen Thread hat. Daher wird immer nur ein Kern verwendet.