Das Symptom
In einem Monorepo hat jemand den Sparse-Checkout entdeckt: git sparse-checkout set src/app, und der Arbeitsbaum ist angenehm klein. Eine Woche später braucht er zusätzlich src/lib, tippt git sparse-checkout set src/lib, und src/app ist weg. git status meldet nichts. Kein Fehler, keine Warnung, keine als gelöscht markierten Dateien. Der Editor zeigt offene Dateien, die es auf der Platte nicht mehr gibt, und der Build scheitert an fehlenden Importen.
Der erste Verdacht fällt auf ein kaputtes Repository, der zweite auf einen Kollegen, der etwas gelöscht hat. Beides falsch.
Die „Layer 8“-Wahrheit
set und add sind keine Synonyme. Die Dokumentation von git sparse-checkout beschreibt set als Befehl, der die Konfiguration aktiviert und dann die Sparse-Checkout-Datei aus den Argumenten füllt, „and update the working directory to match.“ Die Argumente sind die neue Auswahl, vollständig. Für das Ergänzen gibt es add, das die Datei um weitere Verzeichnisse erweitert. Wer set mit einem einzelnen Ordner aufruft, hat genau diesen einen Ordner bestellt, und Git liefert genau das.
Dass git status schweigt, ist ebenfalls dokumentiert. Ein Sparse-Checkout verändert den Arbeitsbaum „from having all tracked files present to only having a subset of those files“, und die übrigen Befehle wissen das: Beim Zweigwechsel werden Pfade außerhalb der Auswahl nicht angefasst, und „git commit -a will not record paths outside the sparse-checkout directories/patterns as deleted.“ Die Dateien sind nicht gelöscht, sie sind nur nicht ausgecheckt. Die Objekte liegen weiter im Repository, und disable bringt den vollständigen Arbeitsbaum zurück.
Der Kegelmodus erklärt eine zweite Verwunderung: Warum liegen Dateien im Wurzelverzeichnis und in den Elternordnern, die niemand angefordert hat? Weil der Kegel so definiert ist. Für ein angegebenes Verzeichnis sind alle Pfade darunter enthalten, dazu alle Dateien unmittelbar in den führenden Verzeichnissen bis hinauf zur Wurzel. „Also, in cone mode, even if no directories are specified, then the files in the toplevel directory will be included.“ Das ist kein Leck in der Auswahl, sondern die Garantie, dass Build-Skripte und Konfiguration an der Wurzel immer da sind.
Zwei Warnungen aus derselben Seite gehören dazu. Erstens trägt das Kommando die Kennzeichnung als experimentell, in Großbuchstaben; sein Verhalten und das anderer Befehle in Sparse-Checkouts kann sich ändern. Zweitens ist der Mustermodus abgekündigt: „For all these reasons, non-cone mode is deprecated. Please switch to using cone mode.“ Anleitungen, die Muster im Stil von .gitignore in die Sparse-Checkout-Datei schreiben, beschreiben einen Zustand, von dem die Dokumentation heute abrät.
Und ein Detail für den Alltag: Nach einem Merge oder Rebase können laut Dokumentation Pfade außerhalb der Auswahl im Arbeitsbaum auftauchen, weil Git sie zum Anzeigen von Konflikten braucht. Auch das ist kein Zurücksetzen der Auswahl; reapply wendet die Regeln neu an. Wer das Werkzeug mit den vier Unterbefehlen list, add, set und disable bedient, hat keinen Grund mehr, nach verschwundenen Dateien zu suchen. Sie liegen genau dort, wo Git sie laut list ablegen soll.