Wer hat Angst vor dem Garbage Collector?

Posted by Start Bootstrap on May 28, 2012

Git arbeitet mit einem Garbage-Collector, der nicht mehr benötigte Objekte abräumt. Einerseits kann man ihn direkt mit git gc aufrufen, andererseits wird er bei manchen Befehlen implizit mit ausgeführt. Das hat bei mir immer ein ungutes Gefühl hinterlassen. Was löscht Git dabei eigentlich? Mache ich mit einem git gc alles kapput?

Die Hilfe (git help gc) beginnt mit: “Runs a number of housekeeping tasks …”. Hmmm, nicht sehr hilfreich. Es folgt die Git-typische längliche Auflistung von Optionen und Konfigurationen. Doch dann, fast ganz unten, steht der beruhigende Satz:

git gc tries very hard to be safe about the garbage it collects.

Und es folgt eine detaillierte Auflistung von Dingen, die Git nicht löscht. Dazu gehört alles, was von den aktuellen Branches und Tags referenziert wird. Vor allem gehört aber auch alles (!) dazu, was im Reflog referenziert wird. Man kann Fehler, die man beispielsweise mit reset, amend, rebase oder branch -d gemacht hat, mit Hilfe des Reflogs also leicht wieder korrigieren. filter-branch speichert die Original-Commits in refs/original. Auch diese werden nicht abgeräumt.

Nun stellt sich natürlich die Frage: Was räumt Git denn überhaupt ab? Und wann?

Git wäre nicht Git, wenn das nicht konfigurierbare wäre. Es gibt eine Reihe von Konfigurationsparametern dafür.

git config gc.pruneexpire 2.weeks.ago              #entspricht default

Selbst wenn Objekte nirgends mehr referenziert werden, räumt Git sie frühestens nach zwei Wochen ab. Schon mal ganz beruhigend.

git config gc.reflogexpireunreachable 30.days.ago  #entspricht default

Die Einträge im Reflog für Commits, die durch git commit --amend, git rebase oder ähnliches werden frühestens nach 30 Tagen entfernt. Mindestens so lange sind auch die dazu gehörenden Commits geschützt.

git config gc.reflogexpire 90.day.ago

Einträge im Reflog, die zur aktuellen Historie gehören, werden für mindestens 90 Tage gehalten. Die Commits selber sind ohnedies geschützt, da Git nie einen Vorfahren des aktuellen Standes eines Branches löschen würde.