Expériences · Leçons apprises
Quand le backup manque et qu'un script supprime
Ce compte rendu d'expérience résume un incident survenu lors de la consolidation d'un important volume de documents financiers et fiscaux. Il est anonymisé, mais suit exactement la chaîne d'erreurs technique. L'objectif est de permettre aux exploitants de partages SMB, de miroirs Nextcloud et de dépôts Git d'éviter de commettre les mêmes erreurs.
Situation de départ
Un travailleur indépendant dans le domaine de la recherche et du freelance souhaitait transférer ses documents financiers accumulés au fil des années depuis un partage source (Samba/NAS) vers une nouvelle structure cible organisée par années (dossiers FY2015 … FY2026 ainsi que FY_undatiert). La source contenait des copies fortement redondantes ; en conclusion, une déduplication (« aucun fichier en double ») était prévue.
Ce qui a mal tourné
Deux erreurs se sont combinées pour provoquer une perte de données massive :
- Aucune sauvegarde vérifiée avant le début. Ce n'est qu'a posteriori qu'une sauvegarde externe de 8 To (du 16.08.) a été montée. Si elle avait été vérifiée au préalable, l'erreur suivante aurait eu peu d'impact.
- Un script de déduplication avec une liste de chemins non quotée. La liste des répertoires à parcourir a été transmise sans guillemets à
find. Comme certains chemins contenaient des espaces (par ex.Freigabe/Banken/Konto 1234 5678/2024), le shell a découpé ces chemins. Cela a fait en sorte que les répertoires parents et enfants apparaissaient plusieurs fois comme points de départ —finda listé le même fichier plusieurs fois.
Le script de déduplication comparait les hachages SHA-256 consécutifs et supprimait la seconde entrée « identique ». Comme le même fichier, en raison de la liste multiple, apparaissait comme « duplicat » de lui-même, il a été supprimé — ainsi que toutes les autres occurrences. Des fichiers uniques ont été détruits, pas des copies redondantes.
(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
La récupération
Dès que l'erreur a été détectée, l'opération en cours a été immédiatement arrêtée. Il n'existait pas de dépôt Git local comme source, mais trois autres copies existaient sur le serveur ou en externe :
- Miroir de synchronisation Nextcloud du partage source sur le même serveur → a restitué environ 5 300 fichiers.
- Archives ZIP survivantes dans la structure cible → environ 70 fichiers supplémentaires par simple extraction.
- Sauvegarde externe de 8 To (du 16.08.) → environ 600 fichiers supplémentaires.
- Origine Git (Gitea) pour un sous-dépôt concerné → l'historique complet a pu être reconstruit par clonage.
(~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
Au total, environ 98 % des fichiers supprimés ont pu être restaurés. Les ~2 % restants concernaient des fichiers qui n'existaient dans aucune des copies disponibles (notamment une exportation de boîte mail et quelques documents créés après la sauvegarde).
Pourquoi le concept GitCover est utile ici
Cette histoire montre : quiconque mise sur des structures natives Git retrouve rapidement une capacité de travail après une erreur involontaire — et documente simultanément de manière conforme aux GoBD.
Leçons apprises
- Vérifier la sauvegarde avant, pas après. Idéalement 3-2-1 : 3 copies, 2 supports, 1 hors ligne. Une sauvegarde montée seulement après le dommage ne sert à rien.
- Toujours traiter les chemins en null-delimited et avec guillemets.
find … -print0 | xargs -0plutôt qu'unfind $LISTnon quoté. Les espaces dans les chemins sont le classique tueur de scripts. - La déduplication ne doit jamais supprimer en cas de liste répétée. La bonne approche : conserver exactement une copie par chemin unique + contenu ; si le même fichier est listé plusieurs fois, rien ne doit être supprimé (décision basée sur l'inode ou le hachage + chemin).
- Disposer de plusieurs sources de récupération indépendantes. Miroirs, archives et contrôle de version se complètent ; aucune seule ne suffit.
- Protéger par commit les fichiers du working tree non versionnés. S'ils ne sont que untracked dans le dépôt, un simple
git cleansuffit à les détruire. Un commit les intègre à l'historique.
Conclusion : Un simple appel de variable non quoté suffit à détruire des milliers de fichiers uniques. La récupération n'a été possible que parce que plusieurs copies indépendantes existaient. La structure, le processus et la discipline ne sont pas des sujets de luxe — ce sont la seule protection qui existe.
Partie de la rubrique Expériences. D'autres articles à suivre.