Git workflow
Branch
mainè sempre verde e rilasciabile. Nessun push diretto: si entra via Pull Request.- Branch di lavoro:
<tipo>/<descrizione-breve>, es.feat/langfuse-sessions-pipeline,fix/cursor-batch-size. - Tipi:
feat,fix,refactor,docs,test,chore,perf.
Worktree: un'attività, un worktree
Ogni attività si sviluppa in un worktree suo, sotto .claude/worktrees/<descrizione>/ (già in .gitignore), con il proprio branch <tipo>/<descrizione> staccato da origin/dev. La cartella principale resta su dev: serve a creare worktree e ad aggiornarsi, non a lavorare.
Perché. La cartella principale è condivisa da tutte le sessioni, umane e agenti. Un git checkout lì sposta il branch anche sotto chi ci sta lavorando, e il suo commit successivo finisce sul branch sbagliato: è successo il 14 settembre 2026, con un commit di doc atterrato su feat/lookup-postgres di un'altra sessione. Con un worktree per attività ognuno ha cartella, branch e node_modules propri: le attività avanzano in parallelo e confluiscono su dev via PR.
Ciclo di vita
# 1. Crea: branch nuovo da origin/dev aggiornato
git fetch origin
git worktree add --no-track -b feat/<descrizione> .claude/worktrees/<descrizione> origin/dev
cd .claude/worktrees/<descrizione>
# 2. Setup: node_modules e .env non sono condivisi fra worktree
pnpm install
cp ../../../.env .env # solo se l'attività esegue pipeline contro sistemi reali
# 3. Lavora e committa qui; poi push esplicito del branch e PR verso dev
git push -u origin feat/<descrizione>
gh pr create --base dev
# 4. Dopo il merge: via worktree e branch, dalla cartella principale
cd ../../..
git worktree remove .claude/worktrees/<descrizione>
git branch -d feat/<descrizione>
git push origin --delete feat/<descrizione>Insidie
--no-trackè voluto. Senza, il branch tracciaorigin/deve ungit pushsenza argomenti prova a spingere sudev. Il primo push si fa sempre con-u origin <branch>.- Il nome della cartella ripete la descrizione del branch, così
git worktree listdice subito chi lavora su cosa. - Submodule
noeva-etl-ui: nel worktree è vuoto. Si popola congit submodule update --init noeva-etl-uisolo se l'attività tocca la UI. - Lo stash è condiviso fra tutti i worktree: per mettere da parte lavoro si fa un commit WIP sul proprio branch, così niente finisce nello stash di un'altra sessione.
- Gitdir fuori dalla cartella.
noeva-etlè un submodule dinoeva-server: la sua gitdir è../.git/modules/noeva-etl.git worktree add,fetchecommitscrivono lì, quindi un sandbox che limita le scritture alla cartella di lavoro li fa fallire conOperation not permitted.
Commit (Conventional Commits)
Formato: <tipo>(<scope>): <descrizione>
feat(langfuse-sessions): aggiungi conteggio environment distinti nel fatto
fix(core): correggi conteggio extracted in modalità streaming
docs(adr): registra scelta di Zod per i contratti
test(postgres): copri l'upsert idempotente del sinkRegole:
- Un commit = un cambiamento coerente. Codice + test + doc dello stesso cambiamento stanno insieme.
- Messaggio all'imperativo, in italiano, conciso. Il perché va nel corpo se non ovvio.
Pull Request
- Compila il template PR: cosa, perché, come testato.
- La PR deve passare la CI (typecheck + lint + format + test + coverage). PR rossa non si fonde.
- Almeno una review approvata. Per le pipeline dati, eseguire
/etl-reviewprima di richiedere review. - PR piccole e focalizzate: più facili da rivedere, più sicure da rilasciare.
Definition of Done prima del merge
Vedi CLAUDE.md §5. In sintesi: check verde, test sul nuovo comportamento, doc allineata, idempotenza verificata, nessun segreto.

