Das Problem
Bevor ein Projekt übergeben wird, eine Stelle endet oder ein Laptop oder eine
VM gelöscht wird, muss jemand herausfinden, welche Arbeit nur auf diesem
Rechner liegt. git status beantwortet das für ein Repository und seinen
aktuellen Branch. Auf einem Rechner mit vielen Repositories muss man die
Prüfung in jedem einzelnen von Hand machen, und einige Arten von Resten
übersieht man leicht: Commits auf lokalen Branches, die nie gepusht wurden,
Stashes, Repositories, die nie ein Remote hatten, und Zugangsdaten-Dateien, die
irgendwann committet und später gelöscht wurden.
Wie es funktioniert
git-leftovers durchläuft die
angegebenen Verzeichnisse bis zur Tiefe 6 und behandelt jedes Verzeichnis mit
einem .git-Eintrag als Repository. Das schließt verschachtelte Repositories
und Worktrees ein. Verzeichnisse wie node_modules und .venv werden
übersprungen.
Für jedes Repository ruft es nur lokale Git-Befehle auf:
git status --porcelainfür geänderte und nicht versionierte Dateiengit stash listfür Stashesgit for-each-refmit dem Tracking-Zustand, der angibt, wie viele Commits ein Branch seinem Upstream voraus ist- für Branches ohne Upstream die Zahl der Commits, die in keinem
Remote-Tracking-Branch enthalten sind
(
git rev-list --count <branch> --not --remotes) git log --all --diff-filter=A --name-only, das jede jemals auf irgendeinem Branch hinzugefügte Datei auflistet; die Dateinamen werden mit Mustern wie.env,*.pem,id_rsa,*credentials*.json,.npmrcund.pgpassverglichen (.env.exampleund ähnliche Vorlagen sind ausgenommen)
Der Exit-Code ist 1, wenn ein Repository Reste hat, und 0, wenn alles gepusht
ist. Das Werkzeug taugt damit auch als Prüfung in Skripten. --json gibt pro
Repository eine Liste findings aus.
Das ist das Beispiel aus dem README (die Pfade sind dort als Beispielpfade gekennzeichnet):
$ git-leftovers ~/work
/home/dev/work/billing-service [main] (no remote)
- no remote: the whole repository exists only here
- 1 modified file(s)
- branch main: 4 unpushed commit(s)
- secret-looking file in history: .env
/home/dev/work/data-pipeline [main]
- 1 untracked file(s)
- branch fix/rounding: 1 commit(s), branch not on any remote
/home/dev/work/warehouse [main]
- 1 stash(es)
12 repositories, 3 with work that exists only here.
Das Werkzeug braucht Python 3.10 oder neuer und git, sonst keine
Abhängigkeiten.
Tests
Die Tests legen echte Git-Repositories in einem temporären Verzeichnis an, mit
einem Bare-Repository als Remote. Ein vollständig gepushter Klon darf keine
Befunde liefern. Davon ausgehend fügen die Tests eine geänderte Datei, eine
nicht versionierte Datei und einen Stash hinzu, zwei ungepushte Commits auf
main und einen lokalen Feature-Branch mit einem Commit, der als "branch not
on any remote" gemeldet werden muss. Ein lokaler Branch ohne neue Commits darf
nicht gemeldet werden, ein Repository ohne Remote dagegen schon.
Ein Test committet .env, löscht die Datei und pusht. Die Datei muss trotzdem
aus der Historie gemeldet werden, und --no-history muss diese Prüfung
überspringen. Eine Tabelle von Dateinamen prüft die Muster:
deploy/.env.production und certs/server.pem passen, .env.example und
src/credentials.py nicht. Ein weiterer Test prüft, dass ein verschachteltes
Repository gefunden und eines in node_modules übersprungen wird. Der
Kommandozeilentest prüft die Exit-Codes und die JSON-Ausgabe.
Es sind 16 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 mit
--all auf dem eigenen Checkout auf.
Grenzen
- Es führt kein Fetch aus. Ein veralteter Remote-Tracking-Stand erscheint als
"unpushed". Wenn das wichtig ist, sollte vorher
git fetch --alllaufen. - Die Prüfung auf Zugangsdaten vergleicht nur Dateinamen. Dateiinhalte liest sie nicht.
- Eine verdächtige Datei in der Historie ist kein Beweis für ein Leck;
Zertifikate (
*.pem) sind oft öffentlich. Der Befund bedeutet, dass sich jemand die Datei ansehen sollte, bevor die Historie den Rechner verlässt. - Repositories, die tiefer liegen als die Suchtiefe (Standard 6), werden nicht gefunden.
Code und Installationsanleitung liegen unter github.com/Jwrede/git-leftovers.