Ich konnte die beliebteste Antwort nicht verwenden, da der --batch-check
Befehlszeilenwechsel zu Git 1.8.3 (den ich verwenden muss) keine Argumente akzeptiert. Die folgenden Schritte wurden unter CentOS 6.5 mit Bash 4.1.2 ausprobiert
Schlüssel Konzepte
In Git der Begriff Blob impliziert den Inhalt einer Datei. Beachten Sie, dass ein Commit möglicherweise den Inhalt einer Datei oder eines Pfadnamens ändert. Daher kann dieselbe Datei je nach Festschreiben auf einen anderen Blob verweisen. Eine bestimmte Datei kann in einem Commit die größte in der Verzeichnishierarchie sein, in einem anderen jedoch nicht. Die Frage, große Commits anstelle großer Dateien zu finden, bringt die Sache daher in die richtige Perspektive.
Für den 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
Beispielausgabe:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620
Verwenden Sie zum Entfernen solcher Blobs den BFG Repo Cleaner , wie in anderen Antworten erwähnt. Bei einer Datei blobs.txt
, die nur die Blob-Hashes enthält, zum Beispiel:
3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2
Tun:
java -jar bfg.jar -bi blobs.txt <repo_dir>
Die Frage ist, wie man die Commits findet, was mehr Arbeit ist als das Finden von Blobs. Um es zu wissen, lesen Sie bitte weiter.
Weitere Arbeit
Bei einem Commit-Hash lautet ein Befehl, der Hashes aller damit verbundenen Objekte, einschließlich Blobs, druckt:
git ls-tree -r --full-tree <commit_hash>
Wenn also solche Ausgaben für alle Commits im Repo verfügbar sind und ein Blob-Hash vorliegt, stimmen die Commits mit den Ausgaben überein. Diese Idee ist im folgenden Skript codiert:
#!/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 gespeichert wird, lautet find-commits.sh
ein typischer Aufruf wie folgt:
cat blobs.txt | find-commits.sh
Wie zuvor blobs.txt
listet die Datei Blob-Hashes auf, einen pro Zeile. Die create_db()
Funktion speichert einen Cache aller Festschreibungslisten in einem Unterverzeichnis im aktuellen Verzeichnis.
Einige Statistiken aus meinen Experimenten mit einem System mit zwei Intel (R) Xeon (R) CPU E5-2620 2,00-GHz-Prozessoren, die vom Betriebssystem als 24 virtuelle Kerne dargestellt werden:
- Gesamtzahl der Commits im Repo = fast 11.000
- Dateierstellungsgeschwindigkeit = 126 Dateien / s. Das Skript erstellt pro Commit eine einzelne Datei. Dies tritt nur auf, wenn der Cache zum ersten Mal erstellt wird.
- Aufwand für die Cache-Erstellung = 87 s.
- Durchschnittliche Suchgeschwindigkeit = 522 Commits / s. Die Cache-Optimierung führte zu einer Reduzierung der Laufzeit um 80%.
Beachten Sie, dass das Skript Single-Threaded ist. Daher wird immer nur ein Kern verwendet.