Files
fn_registry/docs/adr/0005-keep-parent-git-lean.md
T
egutierrez ea6a3ec8a5 chore: auto-commit (3 archivos)
- docs/adr/README.md
- docs/adr/0005-keep-parent-git-lean.md
- docs/diary/2026-06-03.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 12:50:09 +02:00

7.4 KiB
Raw Blame History

ADR 0005 — Mantener el .git del repo padre ligero: no trackear artefactos hijos, purgar basura del historial, submódulos shallow

  • Fecha: 2026-06-03
  • Estado: accepted

Contexto

El .git del repo padre fn_registry había crecido a 475 MB, un tamaño que ralentiza clones, fn sync y la operación diaria entre los tres PCs del ecosistema (aurgi-pc, home-wsl, lucas-linux). El diagnóstico identificó tres causas independientes, todas evitables:

  1. Artefactos hijos forzados al índice. Pese a que el .gitignore ya tiene las reglas correctas (apps/*/, analysis/*/, projects/*/), un .gitignore no des-trackea archivos que ya estaban en el índice. Dos apps tenían contenido forzado: apps/dag_engine/ (31 archivos: código Go + frontend + app.md + README.md) y apps/shaders_lab/ (app.md + un binario shaders_lab.exe). El commit d8db05e9 ("chore(dag_engine): app.md ... metadata trackeada por el padre") había trackeado dag_engine deliberadamente; esta decisión queda anulada. La convención correcta ya estaba demostrada por projects/*/apps (p.ej. registry_dashboard, call_monitor), que el padre no versiona en absoluto y funcionan bien.

  2. Basura en el historial. Versiones antiguas de directorios que nunca debieron versionarse seguían viviendo en los commits pasados: frontend/node_modules (168 MB de binarios), build/ raíz (54 MB de artefactos de compilación C++, 2299 archivos), registry.db (29 MB en ~7 versiones; regenerable con fn index) y apps/shaders_lab/shaders_lab.exe (~190 MB acumulados en ~10 versiones). En total ~440 MB de blobs muertos.

  3. Submódulos C++ con historia completa. cpp/vendor/{imgui,implot,implot3d,tracy,glfw,sdl3} + emsdk son submódulos git legítimos (deps necesarias para compilar las apps imgui). Cada uno clonaba toda la historia upstream: .git/modules pesaba 338 MB para servir un working tree de 118 MB. imgui solo: 129 MB de .git (11.552 commits) para 8.9 MB de headers; sdl3: 146 MB (21.539 commits) para 55 MB de código. El proyecto compila contra un único commit pinneado por submódulo — el resto es historia ajena que nadie consulta.

Decisión

Mantener el .git del padre ligero con tres medidas:

  1. El repo padre NO versiona el contenido de los artefactos hijos. Cada app/analysis/project-app es un sub-repo Gitea independiente con su propio .git (ADR 0002); el padre solo conserva su metadata en registry.db (regenerable con fn index, que lee los artefactos del disco). Se sacan del índice con git rm -r --cached (con --cached SIEMPRE — sin él se borraría el working tree de los sub-repos). Único contenido versionado bajo apps/ y analysis/: los marcadores .gitkeep. Bajo projects/: solo los project.md.

  2. El historial pasado se purga de basura con git filter-repo. Se eliminan los blobs de frontend/node_modules, build/ (raíz), registry.db y apps/shaders_lab/shaders_lab.exe de todos los commits. Esto reescribe la historia (cambian los SHAs) y requiere git push --force. Se añade build/ (raíz) al .gitignore para evitar reincidencia (node_modules, *.exe y registry.db ya estaban).

  3. Los submódulos C++ se configuran shallow (depth 1). Cada submódulo descarga solo el commit pinneado, no la historia upstream. Se marca shallow = true en .gitmodules para que los clones futuros nazcan shallow. El working tree mantiene el snapshot completo de cada dependencia, así que la compilación C++ no cambia.

Cómo se ejecutó (2026-06-03)

# 1. Untrack del índice (los archivos quedan en disco; los .git de los sub-repos conservan el código)
git rm -r --cached apps/dag_engine apps/shaders_lab
git commit -m "chore: untrack contenido de artefactos hijos (dag_engine, shaders_lab)"

# 2. Purga del historial (con git-filter-repo, descargado standalone)
python3 git-filter-repo --strip-blobs-bigger-than 10M --force
python3 git-filter-repo --invert-paths --path frontend/node_modules --path build \
  --path registry.db --path apps/dag_engine --path apps/shaders_lab --force
git remote add origin <url>   # filter-repo elimina el remote por seguridad
git push --force origin master

# 3. Submódulos shallow (deinit + borrar el .git/modules full + re-clone --depth 1)
for sm in cpp/vendor/{sdl3,imgui,tracy,glfw,implot,implot3d} emsdk; do
  git submodule deinit -f "$sm"
  rm -rf ".git/modules/$sm"        # clave: deinit NO borra .git/modules
  git -c "submodule.$sm.shallow=true" submodule update --init --depth 1 "$sm"
done
sed -i '/^\turl = /a\\tshallow = true' .gitmodules
git commit -m "chore: submodulos C++ en modo shallow (depth 1)" && git push origin master

Resultado: .git 475 MB → 51 MB (89%). Desglose: .git/objects 137 MB → 16 MB (historial del registry limpio); .git/modules 338 MB → 35 MB (submódulos shallow). cpp/vendor en disco intacto (118 MB). cmake configure de cpp/ OK con las deps shallow. Backup completo del .git pre-purga en ~/backups/fn_registry_purge_20260603/.

Alternativas descartadas

  • Solo git rm --cached sin purgar el historial. Detiene el crecimiento futuro pero deja los ~440 MB de basura en los commits pasados. No reduce el .git. Insuficiente para el objetivo.
  • Purgar solo shaders_lab.exe. Mismo coste (force-push + re-clone en otros PCs) por mucha menos ganancia: deja node_modules, build/ y registry.db en el historial.
  • Borrar o purgar los submódulos C++. Son deps legítimas necesarias para compilar las apps imgui. Purgarlas rompería la compilación. La vía correcta es shallow, no eliminación.
  • git filter-branch en vez de git-filter-repo. Más lento, deja refs/original y es propenso a errores. filter-repo es la herramienta recomendada por el propio git.

Consecuencias

  • Force-push reescribe la historia del padre. Los otros PCs (aurgi-pc, home-wsl) quedan con historia divergente y deben re-sincronizar: git fetch origin && git reset --hard origin/master && git submodule update --init --recursive. Trabajo local del padre sin pushear se pierde — verificar antes. Esta es la única parte irreversible y outward-facing; requiere confirmación humana explícita.
  • Shallow es local y reversible. No toca el repo padre ni los gitlinks; solo adelgaza el .git interno de cada submódulo. Reversible por dep con git fetch --unshallow. El .gitmodules con shallow = true hace que los clones frescos nazcan ligeros; los clones existentes deben re-aplicar el deinit + rm .git/modules/<x> + update --depth 1 o re-clonar.
  • Bumpear una dep shallow cuesta un git fetch --depth 1 <commit> extra antes del checkout, porque el commit nuevo no está en el clon mínimo. Es fricción, no bloqueo.
  • Se pierde git log/blame/bisect dentro de los submódulos (la historia de SDL3/imgui), algo que casi nunca se hace en deps vendored.
  • Operación repetible. Si el .git vuelve a crecer por basura, el procedimiento de este ADR (untrack + filter-repo + shallow) es el runbook.

Relación con otras reglas y ADRs

  • ADR 0002 — apps/analyses como sub-repos dataforge/<name>. Este ADR refuerza su corolario: el padre no versiona su contenido.
  • .claude/rules/apps_subrepo.md — gotcha de pérdida de código en worktrees; misma raíz (artefactos = sub-repos independientes).
  • .claude/rules/db_locations.mdregistry.db solo en la raíz y regenerable; por eso es purgable del historial.