Illustration: Fehlerhaftes Deduplizierungs-Skript löscht Dateien; Recovery über Git-Repo, Nextcloud-Spiegel und Backup

Dieser Erfahrungsbericht fasst einen Incident zusammen, der sich bei der Konsolidierung einer größeren Menge Finanz- und Steuerunterlagen ereignet hat. Er ist anonymisiert, folgt aber exakt der technischen Fehlerkette. Ziel ist es, Betreiber von SMB-Freigaben, Nextcloud-Spiegeln und Git-Repositories davor zu bewahren, die gleichen Fehler zu machen.

Ausgangslage

Ein Einzelunternehmer im Forschungs- und Freelance-Umfeld wollte seine jahrelang gewachsenen Finanzdokumente von einer Quell-Freigabe (Samba/NAS) in eine neue, nach Jahren geordnete Zielstruktur (Ordner FY2015FY2026 sowie FY_undatiert) überführen. Die Quelle enthielt stark redundante Kopien; als Abschluss war eine Deduplizierung („keine Datei doppelt“) geplant.

Was schiefging

Zwei Fehler kombinierten sich zu einem massiven Datenverlust:

  1. Kein verifiziertes Backup vor Beginn. Erst im Nachgang wurde ein externes 8-TB-Backup (vom 16.08.) eingehängt. Wäre es vorher geprüft worden, hätte der folgende Fehler kaum geschadet.
  2. Ein Deduplizierungs-Skript mit unquotierter Pfadliste. Die Liste der zu durchsuchenden Verzeichnisse wurde unquotiert in find übergeben. Da einige Pfade Leerzeichen enthalten (z. B. Freigabe/Banken/Konto 1234 5678/2024), spaltete die Shell diese Pfade auf. Das führte dazu, dass Eltern- und Kindverzeichnisse mehrfach als Startpunkte erschienen — find listete dieselbe Datei mehrfach auf.

Das Dedup-Skript verglich aufeinanderfolgende SHA-256-Hashes und löschte den jeweils zweiten „gleichen“ Eintrag. Da dieselbe Datei durch die mehrfache Auflistung als „Duplikat“ ihrer selbst erschien, wurde sie — zusammen mit allen weiteren Auflistungen — gelöscht. Es wurden einzigartige Dateien vernichtet, keine redundanten Kopien.

flowchart TD A["Verzeichnisliste SCOPE unquotiert
(find $SCOPE)"] --> B["Shell trennt Pfade mit
Leerzeichen in Fragmente"] B --> C["Eltern- und Kindverzeichnisse
erscheinen mehrfach als Startpunkte"] C --> D["find listet dieselbe Datei
N-mal (N > 1)"] D --> E["Dedup: aufeinanderfolgende
Hash-Werte vergleichen"] E --> F["h == prev bei wiederholter
Listung derselben Datei"] F --> G["rm der 'Duplikate' =
Löschung einzigartiger Dateien"] G --> H["~6.400 einzigartige Dateien
vernichtet"] style G fill:#c0392b,color:#fff style H fill:#c0392b,color:#fff

Die Rettung

Sobald der Fehler bemerkt wurde, wurde die laufende Operation sofort gestoppt. Es gab kein lokales Git-Repository als Quelle, aber drei weitere Kopien existierten auf dem Server bzw. extern:

flowchart LR D["Gelöschte Dateien
(~6.400)"] --> M["Nextcloud-Sync-Spiegel
der Quelle"] D --> Z["Überlebende ZIP-Archive"] D --> B["Externes 8-TB-Backup
(16.08.)"] D --> G["Git-Origin (Gitea)
für Teil-Repo"] M -->|"~5.300"| R["Wiederhergestellt"] Z -->|"~70"| R B -->|"~600"| R G -->|"History"| R R --> S["~98 % gerettet
(~6.300 von ~6.400)"] style S fill:#27ae60,color:#fff

Insgesamt konnten rund 98 % der gelöschten Dateien wiederhergestellt werden. Die verbleibenden ~2 % entfielen auf Dateien, die in keiner der verfügbaren Kopien existierten (u. a. ein Postfach-Export und einige nach dem Backup angelegte Dokumente).

Warum das GitCover-Konzept hier hilft

Die Geschichte zeigt: Wer auf Git-native Strukturen setzt, kommt auch nach unbeabsichtigten Fehlern schnell wieder arbeitsfähig — und dokumentiert zugleich GoBD-konform.

Git-Repos als Sicherheitsnetz. Ein Commit macht unversionierte Arbeitsdateien zum Bestandteil der History. Ein unbeabsichtigter Lösch- oder Überschreibfehler (auch durch ein Skript) lässt sich jederzeit aus dem Repo wiederherstellen — man kann weiterarbeiten, statt von vorne zu beginnen.
GoBD, DSGVO & NIS2 entschärft. Gerade gesetzliche Pflichten — GoBD-Aufbewahrung, DSGVO-Nachweise oder NIS2-Meldungen — lassen sich mit versionierten, nachvollziehbaren Artefakten sauber dokumentieren. Ein Vorfall wird zum protokollierten, reproduzierbaren Ereignis statt zum unauflösbaren Problem.
KI-Agenten auf Daten losgelassen. Auch beim Einsatz von Agenten, die automatisiert auf Daten zugreifen, helfen die Basis-Konzepte von GitCover: klare Herkunft (SHA-256), unveränderliche History und unabhängige Kopien (Spiegel, Backup, Origin) begrenzen Schäden und machen jede Aktion revisierbar.

Lessons Learned

Fazit: Ein einziger unquotierter Variablenaufruf genügt, um Tausende einzigartige Dateien zu vernichten. Die Rettung gelang nur, weil mehrere unabhängige Kopien existierten. Struktur, Prozess und Disziplin sind keine Luxus-Themen — sie sind der einzige Schutz, den es gibt.

Teil der Rubrik Erfahrungen. Weitere Beiträge folgen.