Ilustración: Un script de deduplicación defectuoso borra archivos; recuperación mediante repositorio Git, espejo de Nextcloud y copia de seguridad

Este informe de experiencia resume un incidente que se produjo durante la consolidación de un gran volumen de documentos financieros y fiscales. Está anonimizado, pero sigue exactamente la cadena de errores técnicos. El objetivo es evitar que los administradores de comparticiones SMB, espejos de Nextcloud y repositorios Git cometan los mismos errores.

Situación inicial

Un autónomo en el ámbito de la investigación y el trabajo freelance quería trasladar sus documentos financieros, acumulados a lo largo de los años, desde una compartición de origen (Samba/NAS) a una nueva estructura de destino organizada por años (carpetas FY2015FY2026 y FY_undatiert). El origen contenía copias fuertemente redundantes; como paso final se planeaba una deduplicación («ningún archivo duplicado»).

Lo que salió mal

Dos errores se combinaron para provocar una pérdida masiva de datos:

  1. No se verificó una copia de seguridad antes de comenzar. Solo después se montó una copia de seguridad externa de 8 TB (del 16.08.). Si se hubiera comprobado antes, el siguiente error apenas habría causado daño.
  2. Un script de deduplicación con una lista de rutas sin comillas. La lista de directorios a buscar se pasó sin comillas a find. Dado que algunas rutas contenían espacios (p. ej. Freigabe/Banken/Konto 1234 5678/2024), la shell dividió esas rutas. Esto provocó que los directorios padre e hijo aparecieran múltiples veces como puntos de partida — find enumeró el mismo archivo varias veces.

El script de deduplicación comparaba hashes SHA-256 consecutivos y eliminaba la segunda entrada «idéntica». Dado que el mismo archivo, por la enumeración repetida, aparecía como «duplicado» de sí mismo, se eliminó — junto con todas las demás enumeraciones —. Se destruyeron archivos únicos, no copias redundantes.

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

El rescate

En cuanto se detectó el error, se detuvo de inmediato la operación en curso. No existía ningún repositorio Git local como fuente, pero había tres copias adicionales en el servidor o en medios externos:

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

En total se pudieron recuperar alrededor del 98 % de los archivos eliminados. El ~2 % restante correspondía a archivos que no existían en ninguna de las copias disponibles (entre otros, una exportación de bandeja de entrada y algunos documentos creados después de la copia de seguridad).

Por qué el concepto de GitCover ayuda aquí

La historia demuestra: quien apuesta por estructuras nativas de Git puede volver a trabajar rápidamente incluso tras errores involuntarios — y al mismo tiempo documenta conforme a GoBD.

Repositorios Git como red de seguridad. Un commit convierte archivos de trabajo no versionados en parte del historial. Un error de borrado o sobrescritura involuntario (también por un script) puede recuperarse en cualquier momento desde el repositorio — se puede seguir trabajando en lugar de empezar de cero.
GoBD, RGPD y NIS2 mitigados. Justamente las obligaciones legales — la retención GoBD, las pruebas de RGPD o las notificaciones NIS2 — pueden documentarse de forma limpia con artefactos versionados y trazables. Un incidente se convierte en un evento protocolizado y reproducible en lugar de un problema irresoluble.
Agentes de IA sueltos sobre datos. Incluso al desplegar agentes que acceden automáticamente a datos, los conceptos básicos de GitCover ayudan: un origen claro (SHA-256), un historial inmutable y copias independientes (espejo, copia de seguridad, origen) limitan los daños y hacen que cada acción sea revisable.

Lessons Learned

Conclusión: Una sola llamada a variable sin comillas basta para destruir miles de archivos únicos. El rescate solo fue posible porque existían varias copias independientes. La estructura, el proceso y la disciplina no son temas de lujo — son la única protección que existe.

Parte de la sección Experiencias. Más artículos próximamente.