modulo 07 / lezione 34

Casi reali, debugging della storia, recupero

Submodule e alternative (subtree, monorepo)

Conoscere submodule e capire perché spesso una soluzione diversa è migliore.

60 min Git e controllo versione

Submodule e alternative (subtree, monorepo)

Un submodule è un repository Git dentro un altro repository Git. Il repo principale non salva i file del submodule come normali file: salva un riferimento a uno specifico commit del repository esterno, più la configurazione in .gitmodules.

È potente, ma richiede disciplina. Molti problemi con i submodule nascono dal trattarli come semplici cartelle.

Perché questa lezione conta

Prima o poi un team deve condividere codice tra progetti: librerie interne, temi, SDK, componenti, documentazione, strumenti di build. Git offre submodule e subtree, ma spesso la scelta migliore è un package versionato o un monorepo.

La competenza non è “sapere il comando submodule”. È scegliere il modello giusto per il ciclo di lavoro del team.

Obiettivo operativo

Alla fine della lezione devi saper aggiungere, clonare e aggiornare un submodule, riconoscere i suoi rischi operativi e confrontarlo con subtree, package manager e monorepo.

Come funziona un submodule

Aggiunta:

git submodule add git@github.com:org/lib.git vendor/lib
git commit -m "build: aggiungi submodule lib"

Git crea o aggiorna:

.gitmodules
vendor/lib -> gitlink verso uno SHA specifico

Nel repo principale il submodule è registrato come commit preciso, non come “ultimo main”. Questo è utile per riproducibilità, ma significa che aggiornare la libreria richiede un commit anche nel repo principale.

Clonare correttamente

Clonazione diretta:

git clone --recurse-submodules <repo>

Se hai già clonato:

git submodule update --init --recursive

Dopo un pull che cambia SHA del submodule:

git submodule update --recursive

Senza questi comandi, la cartella può restare vuota o puntare a un commit diverso da quello atteso.

Aggiornare un submodule

Per spostare il submodule a una versione nuova:

cd vendor/lib
git fetch origin
git switch main
git pull --ff-only
cd ../..
git status
git add vendor/lib
git commit -m "build: aggiorna lib submodule"

Il commit finale nel repo principale registra il nuovo SHA del submodule.

git submodule update --remote può automatizzare parte del processo, ma va usato con attenzione: devi comunque controllare cosa stai portando dentro.

Rischi frequenti

Detached HEAD nel submodule. Dopo submodule update, spesso sei su uno SHA, non su un branch. Se fai commit lì senza creare branch, puoi perderne traccia.

CI non configurata. La pipeline deve clonare con submodule o inizializzarli.

Permessi separati. Chi clona il repo principale deve avere accesso anche al repo del submodule.

Review spezzata. La PR del repo principale mostra solo cambio SHA; il diff vero è nel repo del submodule.

Alternative

SoluzioneQuando ha sensoCosto
Submoduledipendenza Git precisa, repo separati, release indipendentionboarding e CI più complessi
Subtreevuoi copiare una dipendenza dentro una cartella mantenendo traccia dell’originesincronizzazione manuale
Package versionatolibreria usata da più progetti con versioni chiareserve pubblicazione pacchetto
Monorepocodice accoppiato, release coordinate, tooling condivisogovernance e build più sofisticate
Copia manualeprototipo o codice statico raramente aggiornatorischio divergenza

Subtree in breve

Esempio:

git subtree add --prefix=vendor/lib git@github.com:org/lib.git main --squash
git subtree pull --prefix=vendor/lib git@github.com:org/lib.git main --squash

Con subtree i file entrano nel repo principale. Chi clona non deve inizializzare nulla. In cambio, aggiornare e contribuire indietro richiede procedure più esplicite.

Criterio decisionale

Scegli submodule solo se:

  1. il repo esterno deve restare davvero indipendente;
  2. vuoi pin esatto a commit specifici;
  3. il team accetta comandi extra in clone, CI e onboarding;
  4. le review cross-repo sono gestite.

Se il codice evolve insieme al progetto, valuta monorepo o workspace. Se è una libreria consumata da molti, valuta package manager e SemVer.

Laboratorio guidato

In un ambiente sandbox:

  1. crea repo app e repo lib;
  2. aggiungi lib come submodule in app;
  3. clona app senza --recurse-submodules e osserva il problema;
  4. inizializza con git submodule update --init --recursive;
  5. fai un commit in lib;
  6. aggiorna il riferimento in app;
  7. ripeti lo scenario con git subtree add.

Output atteso

Una decisione documentata:

Codice condiviso:
Frequenza aggiornamento:
Chi lo modifica:
Serve pin a commit:
Serve release package:
Scelta: submodule / subtree / package / monorepo
Motivo:
Procedura onboarding:
Procedura CI:

Errori comuni

Pensare che submodule sia una cartella normale. È un altro repo.

Dimenticare --recurse-submodules. Il clone non è completo.

Fare commit nel submodule in detached HEAD. Crea lavoro difficile da ritrovare.

Usare submodule per codice che evolve insieme all’app. Spesso un monorepo è più semplice.

Checklist di verifica

  • so aggiungere un submodule;
  • so clonare e inizializzare submodule;
  • so aggiornare lo SHA registrato nel repo principale;
  • so spiegare i rischi in CI e review;
  • so scegliere tra submodule, subtree, package e monorepo.

Collegamenti

  • Modulo: Casi reali, debugging della storia, recupero - lezione 34 del corso.
  • Si collega a tag, SemVer, monorepo e workflow di team.