Architecture Decision Records - ADR260201b

2026/02/01

Bare repository esterno come strategia di isolamento

Autore: Marco Orlandin, Architect
Data: 01 Febbraio 2026
Status: Implementato
Progetto: git-side (open-source, sviluppato per Solexma LLC)
Constraint principali: Zero inquinamento del repo principale, invisibilità totale per collaboratori che non usano git-side, compatibilità con qualsiasi workflow Git esistente

Contesto e problema

git-side deve versionare file che vivono nella directory di un progetto ma non appartengono al suo repository principale. Il meccanismo di storage deve essere completamente invisibile al repo originale: nessun submodule, nessun file di configurazione, nessuna modifica a .git/config.

Il vincolo è rigido: un collaboratore che non usa git-side non deve mai accorgersi della sua esistenza. Niente file estranei in git status, niente hook obbligatori, niente entry in .gitmodules.

La sfida è trovare un meccanismo Git-native che offra tutte le garanzie di versionamento (storia, diff, remote, branch) senza toccare il repo principale.

Requisiti non funzionali

  • Zero file aggiunti al repo principale
  • Nessuna modifica a .git/config o .gitmodules
  • Compatibilità con qualsiasi versione di Git ragionevolmente recente
  • Supporto completo per operazioni Git standard (commit, push, pull, log)
  • Isolamento: errori nel side repo non devono mai impattare il repo principale

Opzioni valutate

Opzione 1: Git submodule

  • Pro: Nativo Git, ben documentato, supporto per remote dedicato.
  • Contro: Modifica .gitmodules nel repo principale. Visibile a tutti i collaboratori. Richiede init esplicito dopo ogni clone. Aggiunge complessità al workflow principale.

Opzione 2: Branch orfano nel repo principale

  • Pro: Zero file aggiuntivi, tutto dentro lo stesso .git.
  • Contro: Inquina la storia del repo principale. Visibile con git branch -a. Rischio di checkout accidentale. Concettualmente sbagliato: mescola storie non correlate.

Opzione 3: Git worktree separato

  • Pro: Supporto nativo per directory di lavoro multiple.
  • Contro: Legato al repo principale (condivide .git). Non isolato: operazioni sul worktree possono interferire. Non pensato per file indipendenti.

Opzione 4: Bare repository esterno con work-tree nella directory del progetto

  • Pro: Isolamento totale: repo separato, storia separata, remote separato. Zero inquinamento. Pattern già validato (vcsh). Supporto completo Git via --git-dir e --work-tree.
  • Contro: Richiede gestione esplicita di GIT_DIR e GIT_WORK_TREE per ogni comando. Location del bare repo da decidere e mantenere.

Decisione

Scelto il bare repository esterno con GIT_DIR puntato al bare repo e GIT_WORK_TREE puntato alla directory del progetto.

Motivazioni principali:

  1. Isolamento perfetto: il repo principale non sa che il side repo esiste.
  2. Git-native: usa meccanismi standard, nessun formato custom.
  3. Pattern validato: ispirato a vcsh, usato da anni nella community.
  4. Flessibilità: supporta remote, branch, log, diff, tutto ciò che Git offre.

Il bare repo vive in una location di sistema: ~/Library/Application Support/git-side/<sha>/ su macOS, ~/.local/share/git-side/<sha>/ su Linux.

Implementazione passo-passo

  1. Init bare repo: git init --bare nella location di sistema, solo al primo git side add (lazy init).
  2. Ogni comando git-side imposta GIT_DIR e GIT_WORK_TREE prima di invocare git, puntando rispettivamente al bare repo e alla directory del progetto.
  3. Pulizia environment: In contesti hook (post-commit), git-side azzera variabili d'ambiente ereditate (GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY) per evitare interferenze con il repo principale.
  4. Hook markers: Gli hook installati sono delimitati da marcatori (# >>> git-side auto >>>) per coesistere con hook esistenti senza conflitti.
  5. Info command: git side info mostra la location del bare repo e lo stato attuale, per debug e trasparenza.

Conseguenze osservate

  • Zero interferenze con il repo principale su tutti i repository testati.
  • Collaboratori senza git-side non vedono alcuna traccia della sua esistenza.
  • L'isolamento dell'environment nelle hook è risultato critico: senza pulizia delle variabili Git ereditate, i comandi del side repo potevano interferire con il repo principale.
  • Lezioni apprese:
    • Il pattern bare repo + work-tree è solido ma richiede attenzione alle variabili d'ambiente, specialmente nei contesti hook.
    • La lazy initialization evita side repo vuoti e inutili.
    • Rendere visibile la location del bare repo (via git side info) è essenziale per il debugging e la fiducia dell'utente.

Stack utilizzato

  • Linguaggio: Rust (Edition 2024, MSRV 1.85)
  • Git: git init --bare, flags --git-dir e --work-tree
  • Path resolution: crate dirs (XDG-compliant)

Quando considerare questo approccio

Se devi versionare contenuti legati a un progetto senza modificare il suo repository:

  • Metadata di progetto (appunti, backlog, scratch)
  • Configurazioni locali dell'ambiente di sviluppo
  • Qualsiasi file che appartiene al contesto del progetto ma non alla sua storia condivisa

Il bare repo esterno è il pattern più pulito quando il vincolo "zero inquinamento" non è negoziabile.

Hai un caso simile? Contattami. Valutiamo insieme se questo pattern fa al caso tuo.