Ein Passwort aus der Git-Historie zu entfernen bedeutet, die Commits, die es enthalten, mit git filter-repo --invert-paths --path <file> umzuschreiben und danach den Reflog ablaufen zu lassen und Garbage Collection auszuführen, damit die alten Commits auch aus .git verschwinden. Mach das erst, nachdem du den Schlüssel rotiert hast — ein geleaktes Secret gilt in dem Moment als kompromittiert, in dem es committet wird, egal ob du die Historie später bereinigst. .gitignore und git rm --cached haben keinerlei Wirkung auf bereits existierende Commits.
1. Prüfen, ob das Secret noch in der Historie steckt
$ clai prüfe, ob dieser Schlüssel noch irgendwo in der Repository-Historie steckt→ git log --all --oneline -S 'sk-live-abc123secret'0fb8c94 stop tracking .env4c1d9ff add app and env
-S findet Commits, bei denen sich die Anzahl der Vorkommen dieses Strings geändert hat — also wo das Secret hinzugefügt und wo es entfernt wurde. Die Suche läuft über die gesamte Historie aller Branches, nicht über das Arbeitsverzeichnis.
2. Bestätigen, dass Entfernen aus dem Index nichts gebracht hat
$ clai hol die Datei .env aus dem Commit, in dem sie hinzugefügt wurde→ git show 4c1d9ff:.envAPI_KEY=sk-live-abc123secret
Das ist das ganze Problem in einem Befehl. .env ist aus dem Arbeitsverzeichnis verschwunden, steht in .gitignore, und git rm --cached wurde bereits ausgeführt — trotzdem holt jeder mit einem Klon das Secret mit einem einzigen Befehl heraus. Der Commit enthält weiterhin den vollständigen Inhalt.
3. Prüfen, in welchen Commits der Pfad vorkommt
$ clai zeig alle Commits, die die Datei .env erwähnen→ git log --all --oneline -- .env0fb8c94 stop tracking .env4c1d9ff add app and env
Das ist die Liste dessen, was umgeschrieben werden muss. Zwei Commits, und du kommst glimpflich davon. Zweihundert, verteilt über mehrere Branches, und du musst dich erst mit dem ganzen Team abstimmen.
4. Erst rotieren, dann bereinigen
Ein Secret, das es in git geschafft hat, muss man als geleakt behandeln, ohne Ausnahme. Das Repository könnte längst geklont, geforkt, von einem Bot indexiert oder von CI gecacht worden sein, bevor der Fehler überhaupt auffällt. Widerrufe den Schlüssel und stelle einen neuen aus, bevor du die Historie anfasst: eine saubere Historie mit einem noch gültigen gestohlenen Schlüssel ist schlimmer als eine unaufgeräumte Historie mit einem bereits widerrufenen.
5. Historie mit dem richtigen Werkzeug umschreiben
$ clai entferne die Datei .env aus der gesamten Repository-Historie→ git filter-repo --invert-paths --path .env⚠ DANGER — rewrites all history, every commit hash changes
git filter-repo ist das, was das git-Projekt selbst empfiehlt. git filter-branch gilt als veraltet: um Größenordnungen langsamer, und bei unvorsichtiger Nutzung kann es ein Repository stillschweigend beschädigen. BFG Repo-Cleaner ist die andere Option: schneller bei großen Repositories und kann einen String durch ***REMOVED*** ersetzen, statt die ganze Datei zu löschen.
6. Aufräumen, was lokal übrig bleibt
$ clai lass alte Refs verfallen und führe aggressive Garbage Collection aus→ git reflog expire --expire=now --all && git gc --prune=now --aggressive
Nach dem Umschreiben bleiben die alten Commits über den Reflog erreichbar — das Secret liegt also weiterhin in .git. Dieser Befehl entfernt sie endgültig. Bei GitHub oder GitLab musst du separat den Support bitten, ihren Cache zu leeren, und um Forks kümmert sich niemand.
Fallstricke
- Eine umgeschriebene Historie zerstört jeden Klon im Team. Nach dem Force-Push muss jeder neu klonen oder
git rebase --ontomachen. Warne die anderen vorher, sonst pusht jemand die alte Historie wieder zurück. - Forks und Pull Requests überleben. Auf GitHub kann ein Commit aus einem geschlossenen PR per Direktlink erreichbar bleiben, selbst nachdem das Hauptrepository bereinigt wurde. Noch ein Grund, den Schlüssel zu rotieren.
git filter-branchist veraltet. Git selbst gibt beim Ausführen eine Warnung aus und verweist auf filter-repo. Die Hälfte der Artikel, die dafür ranken, weiß das noch nicht.
Verwandte Fragen
Reicht es, die Datei in .gitignore einzutragen? Nein. .gitignore betrifft nur neue Dateien. Alles bereits Committete bleibt vollständig in der Historie.
Wie verhindere ich das künftig? Ein Pre-Commit-Hook mit einem Secret-Scanner: gitleaks, detect-secrets oder trufflehog. Sie fangen den Schlüssel vor dem Commit ab, nicht danach.
Was, wenn das Secret schon auf GitHub ist? Sofort den Schlüssel widerrufen, dann die Historie bereinigen, dann den GitHub-Support bitten, gecachte Ansichten zu löschen. Genau in dieser Reihenfolge.
Siehe auch
- Letzten Git-Commit rückgängig machen, Änderungen behalten
- Git-Aufgaben, laut ausgesprochen
- SAFE, CAUTION, DANGER: wie CliAI einstuft, was gerade ausgeführt wird
CliAI stuft git filter-repo als DANGER ein und verlangt eine getippte Bestätigung, bevor auch nur ein Commit angefasst wird. In einer Zeile installieren.