Beschädigte Git-Objekte in Cloud-Mac-CI sicher diagnostizieren und wiederherstellen

Beschädigte Git-Objekte in Cloud-Mac-CI sicher diagnostizieren und wiederherstellen

Wenn eine Pipeline nach checkout plötzlich mit bad object, missing blob oder pack checksum mismatch abbricht, kann ein erneuter Lauf das Problem scheinbar beheben – oder dazu führen, dass mehrere Jobs gleichzeitig ausfallen. Meist liegt der Fehler nicht im Anwendungscode, sondern in einem inkonsistenten Arbeitsbereich, Objekt-Cache oder Git-Packfile. Die richtige Reaktion besteht nicht darin, sofort den Cache zu löschen. Zuerst müssen alle Schreibzugriffe gestoppt und Beweise gesichert werden. Anschließend ist zu klären, ob die Beschädigung nur ein einzelnes Repository oder eine gemeinsam genutzte Ebene betrifft.

Netzwerkfehler von beschädigten Objekten unterscheiden

Netzwerkfehler treten meist während des Abrufs auf. Die Protokolle enthalten dann typischerweise Hinweise auf unterbrochene Verbindungen, ein vorzeitiges Schließen durch die Gegenstelle oder eine unvollständige Übertragung. Beschädigte Objekte fallen dagegen häufig beim Auschecken, Zusammenführen, Lesen des Verlaufs oder Erstellen eines Archivs auf und werden zusammen mit einem konkreten Objekt-Hash gemeldet. Notieren Sie zuerst den fehlgeschlagenen Befehl, den Exit-Code, den Commit, den Pfad des Arbeitsbereichs und die verwendete Cache-Generation. Bewahren Sie nicht nur die letzten Zeilen des Pipeline-Protokolls auf.

Führen Sie zunächst ausschließlich schreibgeschützte Prüfungen aus:

git status --porcelain=v2
git rev-parse --show-toplevel
git rev-parse HEAD
git fsck --full --strict --no-dangling

Meldet git fsck einen missing blob, fehlt ein Dateiobjekt, das über eine Referenz erreichbar sein sollte. Ein missing tree verhindert häufig das Auschecken eines Verzeichnisses. invalid sha1 pointer bedeutet, dass eine Referenz auf ein nicht lesbares Objekt verweist. Werden lediglich dangling objects gemeldet, ist das noch kein Beleg für ein beschädigtes Repository. Solche Objekte können durch einen Rebase, eine Komprimierung oder ersetzte Commits entstanden sein.

Ziel der Diagnose ist es, den Umfang der Beschädigung zu bestimmen – nicht lediglich den aktuellen Befehl vorübergehend erfolgreich auszuführen. Alle Aktionen, die die Objektdatenbank neu schreiben, müssen warten, bis der Vorfall vollständig gesichert wurde.

Arbeitsbereich einfrieren und Beweise sichern

Pausieren Sie zunächst alle Runner, geplanten Abrufe und Cache-Aktualisierungen, die in dasselbe Verzeichnis schreiben. Führen Sie im ursprünglichen Verzeichnis weder git gc noch git prune, ein erneutes Packen oder rekursives Löschen aus. Diese Vorgänge können die Anordnung der Objekte verändern und verhindern, dass sich der ursprüngliche Fehler reproduzieren lässt.

Sichern Sie mindestens das vollständige Job-Protokoll, .git/HEAD, .git/config, .git/packed-refs, .git/refs, .git/logs, den aktuellen Status und alle nicht committeten Änderungen. Der Quellcode-Arbeitsbereich kann nicht verfolgte Dateien enthalten. Prüfen Sie deshalb vor dem Archivieren die Dateiliste, damit nicht versehentlich Zugangsdaten oder große Build-Artefakte mitgesichert werden.

incident="$HOME/git-incidents/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$incident"
git status --porcelain=v2 > "$incident/status.txt"
git show-ref --head > "$incident/refs.txt"
git reflog show --all --date=iso > "$incident/reflog.txt"
git diff --binary > "$incident/worktree.patch"
git diff --cached --binary > "$incident/index.patch"
git fsck --full --strict > "$incident/fsck.txt" 2>&1 || true

Wenn der Arbeitsbereich jederzeit durch das CI-System neu erstellt werden kann, sollte das gesamte Verzeichnis zur Isolation umbenannt werden, statt es an Ort und Stelle zu reparieren. Setzen Sie das isolierte Verzeichnis auf schreibgeschützt und dokumentieren Sie den zugehörigen Job sowie die Herkunft des Caches.

Lose Objekte, Packfiles und gemeinsam genutzte Caches untersuchen

Git-Objekte können als lose Dateien vorliegen oder in einem .pack gespeichert sein. Wenn die Fehlermeldung einen Hash enthält, ermitteln Sie zunächst Typ und Größe des Objekts:

object="0123456789abcdef0123456789abcdef01234567"
git cat-file -t "$object"
git cat-file -s "$object"

Schlagen diese Befehle fehl, prüfen Sie, ob .git/objects/${object:0:2}/${object:2} vorhanden ist. Existiert die Datei, lässt sich aber nicht lesen, wurde ihr Inhalt meist abgeschnitten, stimmt nicht mit der Prüfsumme überein oder wurde auf der darunterliegenden Speicherebene unvollständig kopiert. Überschreiben Sie den Befund nicht mit einer gleichnamigen Datei aus einer Quelle, deren Integrität nicht feststeht.

Validieren Sie bei Packfiles jeden Index einzeln:

for index in .git/objects/pack/*.idx; do
  git verify-pack -v "$index" >/dev/null || printf '%s\n' "$index"
done

Wenn für das Repository Alternates konfiguriert sind, prüfen Sie zusätzlich .git/objects/info/alternates. Nutzen mehrere Jobs dasselbe beschreibbare Objektverzeichnis, kann ein einziger abgebrochener Schreibvorgang alle darauf verweisenden Arbeitsbereiche beeinträchtigen. Das erneute Klonen nur eines Repositorys beseitigt dann nicht die Ursache. Die betroffene Cache-Generation darf nicht weiter veröffentlicht werden.

Reproduzierbarkeit der Beschädigung sicher prüfen

Reproduzieren Sie die Prüfung erst in einer Kopie des isolierten Verzeichnisses. Erfassen Sie dabei auch den freien Speicherplatz des Dateisystems, die Art der Prozessbeendigung und die Anzahl der Jobs im selben Zeitraum. Tritt der Fehler jedes Mal beim gleichen Objekt auf, untersuchen Sie vorrangig die Objektquelle und den Cache. Wechseln die betroffenen Objekte dagegen ständig, sollten Sie Speicherdruck, konkurrierende Schreibzugriffe und die Bereinigungslogik für Arbeitsbereiche überprüfen.

Mit einem sauberen Klon wiederherstellen statt vor Ort zu operieren

Für CI-Arbeitsbereiche ohne manuelle Änderungen besteht der sichere Wiederherstellungsweg normalerweise darin, ein vollständig neues Verzeichnis anzulegen, den Ziel-Commit vollständig abzurufen, die Integrität zu prüfen und anschließend das alte Verzeichnis atomar zu ersetzen. Der neue Klon darf keinen noch nicht validierten Objekt-Cache wiederverwenden.

root="$HOME/ci-workspaces"
next="$root/project.next"
active="$root/project"
failed="$root/project.failed"

rm -rf "$next"
git clone --no-local "$REPOSITORY_PATH" "$next"
git -C "$next" checkout --detach "$EXPECTED_COMMIT"
git -C "$next" fsck --full --strict
test "$(git -C "$next" rev-parse HEAD)" = "$EXPECTED_COMMIT"
mv "$active" "$failed"
mv "$next" "$active"

Führen Sie vor dem Austausch außerdem eine minimale Projektvalidierung durch, etwa das Einlesen des Projekts, das Auflisten der Build-Einstiegspunkte oder eine Reihe schneller Tests. Enthält das isolierte Repository noch nicht übertragene Commits, dürfen Sie nicht davon ausgehen, dass diese durch erneutes Klonen wiederhergestellt werden. Versuchen Sie anhand der gesicherten Referenzen und des Reflogs, sie in einer Kopie auszulesen. Fehlen die benötigten Objekte tatsächlich, können sie nur von einem vertrauenswürdigen Remote, aus einem anderen vollständigen Klon oder aus den ursprünglichen Arbeitsergebnissen rekonstruiert werden.

Objektvalidierung in die Veröffentlichung von Caches integrieren

Ein gemeinsam genutzter Git-Cache sollte nicht von allen Jobs gleichzeitig beschrieben werden. Stabiler ist ein Modell aus „Erzeugen, Validieren, Veröffentlichen“: Ein Job erstellt einen neuen Cache in einem temporären Verzeichnis, führt nach Abschluss des Abrufs git fsck aus und benennt das Verzeichnis erst nach erfolgreicher Prüfung in eine neue schreibgeschützte Generation um. Laufende Jobs bleiben an ihre jeweilige Generation gebunden und wechseln nicht während der Ausführung auf eine Aktualisierung.

Die regelmäßigen Prüfungen lassen sich auf vier Punkte reduzieren: Objekte vor der Cache-Veröffentlichung validieren; Job-Arbeitsbereiche von der gemeinsam genutzten Basis trennen; bei Fehlern Objekt-Hash und Cache-Generation sichern; Bereinigungsskripte nur vollständige Generationen löschen lassen, die nicht mehr referenziert werden. So bleiben unvollständige Schreibvorgänge infolge eines einzelnen fehlgeschlagenen Downloads oder Prozessabbruchs auf ein noch nicht veröffentlichtes temporäres Verzeichnis begrenzt.

Abschließend sollte der Wiederherstellungsablauf als ausführbares Skript vorliegen und in einem Test-Repository ohne geschäftsrelevante Daten überprüft werden. Eine verlässliche Übung muss mindestens nachweisen, dass ein beschädigter Cache nicht weiter verteilt wird, der Ziel-Commit aus einer sauberen Quelle neu aufgebaut werden kann, nicht committete Änderungen einen separaten Sicherungspfad besitzen und während des Austauschs niemals zwei Jobs gleichzeitig in denselben Arbeitsbereich schreiben.

Häufig gestellte Fragen

Sollte eine auffällige Datei direkt aus .git/objects gelöscht werden?

Nein. Zuerst müssen Schreibzugriffe gestoppt sowie Protokolle und Referenzen gesichert werden. Direktes Löschen kann weitere Referenzen unbrauchbar machen und die Diagnose erschweren.

Kann git gc eine beschädigte Objektdatenbank reparieren?

git gc ist kein Reparaturwerkzeug. Es schreibt Objektstrukturen um und entfernt Daten. Bei entbehrlichen CI-Arbeitskopien ist ein sauberer, geprüfter Klon die sicherere Lösung.

Wie verhindert man, dass ein defekter Cache neue Jobs infiziert?

Caches sollten unveränderlich veröffentlicht werden. Ein neuer Stand wird in einem separaten Verzeichnis aufgebaut, mit git fsck geprüft und erst danach per atomarer Umbenennung aktiviert.

Exklusiver physischer Knoten

Wählen Sie einen Cloud-Mac für kontinuierliche Builds

Vergleichen Sie Konfigurationen, Regionen und vier Abrechnungszeiträume von SDKMac M4 und SDKMac M4 Pro und erstellen Sie anschließend Ihre Bestellung.

Mietplan auswählen