Das Problem
Läuft auf einem kleinen Server die Platte voll, ist die erste Frage, was
gewachsen ist. du und ncdu zeigen, was jetzt groß ist. Was sich seit
gestern oder seit letzter Woche verändert hat, zeigen sie nicht. Läuft eine
Platte immer wieder voll, muss man das gewachsene Verzeichnis also jedes Mal
von Hand suchen.
Wie es funktioniert
Jeder Lauf von diskdelta zeichnet die
Größe jedes Verzeichnisses bis zu einer gewählten Tiefe unterhalb eines
Wurzelverzeichnisses auf (Standard: 3 Ebenen) und speichert diesen Snapshot als
JSON-Datei in ~/.local/state/diskdelta. Die letzten 30 Snapshots bleiben
erhalten. Danach vergleicht es den neuen Snapshot mit dem vorherigen und mit dem
neuesten Snapshot, der mindestens sieben Tage alt ist, und gibt beide
Wachstumstabellen sowie die größten Verzeichnisse aus.
Die Größen werden so gemessen, wie du sie meldet: belegte Blöcke, Hardlinks
nur einmal gezählt. Symlinks werden nicht verfolgt, und der Scan bleibt auf dem
Dateisystem des Wurzelverzeichnisses.
Wachsen in /tmp/render-cache 2 GB hinzu, wachsen auch /tmp und / um
2 GB. Damit dieselbe Änderung nicht dreimal erscheint, lässt die
Wachstumstabelle ein Verzeichnis weg, wenn eines seiner aufgezeichneten
Unterverzeichnisse mindestens 90 Prozent seiner Änderung erklärt. Die Tabelle
nennt dann das tiefste Verzeichnis, das das Wachstum erklärt. Verteilt sich die
Änderung auf mehrere Unterverzeichnisse, bleibt das Elternverzeichnis in der
Tabelle.
Mit --min-free 2G gibt es ALERT aus und endet mit Status 2, wenn weniger als
2 GB frei sind. Ein Skript oder Cron-Job kann also auf den Exit-Status
reagieren. Das README schlägt einen täglichen Cron-Eintrag vor:
30 4 * * * timeout 900 diskdelta / --depth 3 --min-free 2G >> ~/diskdelta.log 2>&1
Das ist das Beispiel aus dem README (die Pfade sind dort als Beispielpfade gekennzeichnet):
$ diskdelta / --depth 3 --min-free 2G
2026-10-25 04:30 / free 3.1G
Growth since last run (2026-10-24 04:30, free then 5.6G, change -2.5G):
2.1G /tmp/render-cache
290.4M /home/dev/.cache/uv
61.0M /var/log/journal
Growth since 7 days (2026-10-18 04:30, free then 8.4G, change -5.3G):
2.1G /tmp/render-cache
1.9G /home/dev/.local/share/claude/versions
...
Largest directories:
14.2G /home
...
Das Werkzeug braucht Python 3.10 oder neuer und hat keine Abhängigkeiten.
Tests
Die Scan-Tests schreiben Dateien bekannter Größe in ein temporäres Verzeichnis und prüfen, welche Verzeichnisse bei einer gegebenen Tiefe aufgezeichnet werden und dass Elternverzeichnisse mindestens so groß sind wie ihre Kinder. Ein Test legt einen Hardlink und einen Symlink zurück auf die Wurzel an. Der Hardlink darf nur einmal zählen, und die Schleife darf nicht verfolgt werden.
Die Wachstumstests arbeiten mit Größentabellen. Sie prüfen, dass die Änderung
dem tiefsten Verzeichnis zugeordnet wird, dass ein Elternverzeichnis
verschwindet, wenn ein einzelnes Kind sein Wachstum erklärt, dass es bleibt,
wenn sich zwei Kinder die Änderung teilen, und dass neue und schrumpfende
Verzeichnisse richtig behandelt werden. Weitere Tests decken die Wahl des
Sieben-Tage-Vergleichs, das Einlesen von Größen (2G, 500M, 1.5GiB) und die
lesbare Ausgabe ab.
Der Kommandozeilentest ruft das Werkzeug dreimal auf einem temporären
Verzeichnis auf: Der erste Lauf meldet "no snapshot yet", der zweite listet ein
neu geschriebenes Log-Verzeichnis in der Wachstumstabelle, und ein Lauf mit
--min-free 1000T gibt ALERT aus und liefert 2. Ein weiterer Test prüft, dass
nur die eingestellte Zahl von Snapshots erhalten bleibt.
Es sind 14 Tests. Das CI führt sie auf Python 3.10, 3.11, 3.12 und 3.13 aus,
zusammen mit ruff check und ruff format --check, und ruft das Werkzeug
einmal auf dem eigenen Checkout auf.
Grenzen
- Verzeichnisse werden nur bis zur gewählten Tiefe aufgezeichnet. Wachstum weiter unten wird dem tiefsten aufgezeichneten Verzeichnis darüber zugerechnet.
- Nicht lesbare Verzeichnisse werden übersprungen. Für ein vollständiges Bild
von
/muss das Werkzeug als root laufen. - Andere Dateisysteme, die unterhalb der Wurzel eingehängt sind, fehlen im Ergebnis.
- Die Wachstumstabellen brauchen frühere Snapshots. Der erste Lauf hat keine, und der Sieben-Tage-Vergleich erscheint erst, wenn ein so alter Snapshot existiert.
Code und Installationsanleitung liegen unter github.com/Jwrede/diskdelta.