Architecture Decision Records - ADR260201e

2026/02/01

Self-versioning di .side-tracked via git plumbing

Autore: Marco Orlandin, Architect
Data: 01 Febbraio 2026
Status: Implementato
Progetto: git-side (open-source, sviluppato per Solexma LLC)
Constraint principali: La lista dei file tracciati deve viaggiare con push/pull, non deve vivere nel repo principale, deve essere versionata insieme ai file che descrive

Contesto e problema

git-side tiene traccia di quali file e directory sono "side-tracked", cioè versionati nel side repo. Questa lista deve essere persistente e, soprattutto, deve viaggiare con i dati quando si fa push/pull verso un remote.

Se faccio push dei miei file "a lato" e un collega fa pull, il collega deve sapere quali path sono tracciati. Senza questa informazione, git side auto non saprebbe cosa sincronizzare.

Il problema è dove e come memorizzare questa lista:

  • Non può stare nel repo principale (zero inquinamento).
  • Non può stare solo in un file di configurazione locale (non viaggia con push/pull).
  • Deve vivere dentro il side repo stesso, versionata come qualsiasi altro file.

Ma il side repo è un bare repository e non ha una working directory propria. Il file .side-tracked non esiste su disco nella directory del progetto. Come si aggiunge un file "virtuale" a un bare repo?

Requisiti non funzionali

  • La lista tracciati deve essere versionata nel side repo
  • Deve viaggiare automaticamente con push e pull
  • Non deve creare file nella directory del progetto
  • Deve essere aggiornabile atomicamente ad ogni add/rm

Opzioni valutate

Opzione 1: File di configurazione nella config directory di sistema

  • Pro: Semplice da implementare. Lettura/scrittura immediata.
  • Contro: Non viaggia con push/pull. Ogni macchina avrebbe una lista diversa. Il collega che fa pull non sa cosa tracciare.

Opzione 2: File .side-tracked nella directory del progetto

  • Pro: Visibile, facile da editare, git lo traccia normalmente.
  • Contro: Viola il principio di zero inquinamento. Apparirebbe in git status del repo principale.

Opzione 3: Git notes sul side repo

  • Pro: Meccanismo Git-native per metadati.
  • Contro: Non pensato per questo uso. API scomoda. Non si sincronizza automaticamente con push/pull standard.

Opzione 4: Git plumbing (hash-object + update-index)

  • Pro: Il file vive nell'indice del bare repo senza esistere su disco. Viene committato normalmente. Viaggia con push/pull. Completamente Git-native.
  • Contro: Richiede conoscenza dei comandi plumbing. Implementazione meno intuitiva.

Decisione

Scelto il git plumbing: il file .side-tracked viene scritto nell'indice del bare repo tramite hash-object e update-index, senza mai toccare il filesystem della directory del progetto.

Motivazioni principali:

  1. Self-contained: la lista vive dove vivono i dati che descrive.
  2. Sincronizzazione automatica: push/pull portano la lista insieme ai file.
  3. Versionata: ogni modifica alla lista è un commit, con storia e diff.
  4. Invisibile: nessun file aggiuntivo nella directory del progetto.

Implementazione passo-passo

  1. Scrittura: La lista dei path tracciati (uno per riga, ordinamento deterministico via BTreeSet) viene serializzata in una stringa.
  2. hash-object: git hash-object -w --stdin scrive il contenuto nel database oggetti del bare repo e restituisce lo SHA.
  3. update-index: git update-index --add --cacheinfo 100644,<sha>,.side-tracked aggiunge il file all'indice con il nome .side-tracked.
  4. Commit: Il file viene incluso nel prossimo commit del side repo insieme ai file tracciati.
  5. Lettura: Al pull, .side-tracked viene estratto dall'albero del commit e usato per ricostruire la lista dei path.

Conseguenze osservate

  • La lista viaggia correttamente con push/pull: chi clona il side repo sa esattamente cosa tracciare.
  • L'ordinamento deterministico (BTreeSet) garantisce che la lista sia identica indipendentemente dall'ordine di aggiunta.
  • Nessun file .side-tracked appare mai nella directory del progetto.
  • Lezioni apprese:
    • I comandi plumbing di Git sono potenti e sottovalutati. hash-object + update-index risolvono elegantemente il problema dei "file virtuali" nei bare repo.
    • Il self-versioning elimina un'intera classe di problemi di sincronizzazione.
    • Documentare il meccanismo è importante: il plumbing non è ovvio per chi legge il codice per la prima volta.

Stack utilizzato

  • Linguaggio: Rust (Edition 2024, MSRV 1.85)
  • Git plumbing: git hash-object, git update-index
  • Struttura dati: BTreeSet per ordinamento deterministico e deduplicazione

Quando considerare questo approccio

Se devi versionare metadati o file di configurazione dentro un bare repository senza toccare la working directory:

  • Tool che gestiscono repository Git dall'esterno
  • Sistemi che devono sincronizzare metadata insieme ai dati
  • Qualsiasi contesto in cui un file deve "vivere" nel repo senza esistere su disco

Il plumbing Git è la risposta. È meno accessibile del porcelain, ma risolve problemi che il porcelain non può affrontare.

Hai un caso simile? Contattami. Valutiamo insieme se il plumbing è la strada giusta.