Il 23 febbraio 2004 CollabNet ha rilasciato Subversion 1.0.0, un sistema di controllo versione centralizzato pensato per sostituire CVS (Concurrent Versions System) senza stravolgerne l’uso quotidiano. La riga di comando resta quella di prima — svn checkout, svn commit, svn update ricalcano la sintassi di CVS — e la differenza vera è nel modo in cui il repository registra le modifiche.

Contesto

CVS è in giro dalla fine degli anni Ottanta e versiona i file uno per uno: ogni file ,v ha la propria storia di revisioni, indipendente dalle altre, e il numero di revisione cresce per file. Da questo modello discendono tre conseguenze pratiche che chiunque abbia gestito un repository CVS condiviso conosce bene.

La prima: non c’è un identificativo unico per lo stato dell’intero progetto a un dato istante. Per riprodurre uno snapshot coerente serve un tag esplicito o un timestamp, e in CVS un tag è un’etichetta appiccicata a ciascun file separatamente. La seconda: il commit non è atomico. Se il processo si interrompe a metà — la rete cade, il server è saturo — alcuni file risultano aggiornati e altri no, e il repository finisce in uno stato che nessuna singola revisione descrive. La terza: CVS non versiona la struttura delle directory. Rinominare un file vuol dire rimuoverlo e riaggiungerlo, e per strada se ne perde la continuità storica.

Subversion nasce nel 2000 dentro CollabNet (Karl Fogel, Ben Collins-Sussman, C. Michael Pilato, con Brian Behlendorf nel gruppo iniziale) attorno a una decisione di progetto: versionare l’intero albero, non i singoli file.

Architettura

Un repository Subversion è una sequenza di alberi. Ogni svn commit andato a buon fine produce un nuovo albero completo e gli assegna un numero di revisione intero, globale e crescente. La revisione 42 non è la revisione 42 di un file: è lo stato dell’intero repository dopo il quarantaduesimo commit. Questo solo cambio di rappresentazione chiude in un colpo i primi due problemi di CVS. Lo snapshot coerente diventa un numero. E il commit che produce la revisione 42 è una transazione sullo storage sottostante: o l’albero nuovo viene scritto e diventa visibile per intero, o non viene scritto affatto.

Al rilascio 1.0 lo storage è un database Berkeley DB: le transazioni del DBMS (database management system) danno direttamente l’atomicità del commit. La scelta ha un costo operativo noto e documentato — un arresto anomalo del processo può lasciare l’ambiente Berkeley DB in uno stato da recuperare con svnadmin recover, e la concorrenza fra letture e scritture va gestita con attenzione al locking. È un compromesso dichiarato, non un dettaglio nascosto sotto il tappeto.

Dato che a essere versionato è l’albero, le directory diventano oggetti di prima classe, con una loro storia. Ne nascono due operazioni che CVS non aveva:

  • copia (svn copy): duplica un nodo dell’albero — file o directory — e annota da quale revisione e percorso arriva. La copia resta interna al repository e non duplica fisicamente i dati: costa quanto un nuovo riferimento, qualunque sia la dimensione del sottoalbero. Branch e tag in Subversion sono esattamente questo: una copia di trunk/ sotto branches/ o tags/, per convenzione e non per un meccanismo dedicato.
  • rinomina come copy più delete nella stessa transazione, con l’origine tracciata: la storia del file sopravvive allo spostamento.

Ogni nodo dell’albero può poi portare con sé delle proprietà (properties): coppie chiave/valore versionate insieme al contenuto. Subversion se ne riserva alcune con prefisso svn:svn:ignore, svn:executable, svn:mime-type, svn:eol-style — e lascia il resto dello spazio dei nomi all’utente. La normalizzazione dei fine-riga e il flag di eseguibilità, che in CVS si gestivano con flag per-file o keyword expansion, qui diventano metadati versionati come qualsiasi altro.

Il punto delicato

La parte meno scontata dell’ingegneria 1.0 è il trasporto di rete. Per l’accesso remoto via HTTP, Subversion non si inventa un protocollo proprietario: implementa WebDAV (RFC 2518) e la sua estensione per il versionamento, DeltaV (RFC 3253, marzo 2002). Il modulo mod_dav_svn si innesta su mod_dav dentro Apache HTTP Server 2, e il repository viene esposto come risorsa DeltaV.

La ricaduta pratica è che autenticazione, autorizzazione, cifratura TLS, log, reverse proxy e bilanciatori già configurati per Apache valgono anche per il repository, senza un secondo stack da tenere in piedi. Un browser può scorrere il repository in sola lettura, perché un repository Subversion servito da mod_dav_svn è, formalmente, un server WebDAV. La scelta sposta complessità dal codice di Subversion all’ecosistema Apache, che a quel punto è maturo da anni.

Chi non vuole Apache ha un trasporto alternativo: il demone svnserve con lo schema svn://, e la variante svn+ssh:// che incanala lo stesso protocollo dentro una sessione SSH, riusando l’autenticazione di sistema.

Implicazioni

Chi arriva da CVS deve rivedere tre abitudini mentali, più che la sintassi. Il commit va pensato come unità indivisibile, quindi raggruppato per cambiamento logico e non per file toccato. La revisione globale rende inutile il tagging file per file: a identificare lo stato basta un numero. E il fatto che branch e tag siano copie sposta la disciplina dal meccanismo alla convenzione di layout — trunk, branches, tags — che il sistema non impone ma incoraggia.

Sul piano operativo, con Apache il repository centrale sta dietro a HTTPS e i permessi li gestisce il web server; e strumenti come TortoiseSVN (integrazione con Windows Explorer, in sviluppo dal 2002) portano lo stesso modello a chi non lavora da riga di comando.

Limiti

Subversion resta centralizzato per scelta: c’è un repository autoritativo, e la working copy locale non ne è una replica con storia propria. Operazioni come log o diff contro revisioni arbitrarie passano dal server. Sistemi che esplorano il modello distribuito esistono — BitKeeper (commerciale, usato nel kernel Linux), GNU Arch, Monotone, darcs — ma oggi con diffusione e maturità d’uso inferiori; su quel terreno Subversion non si mette, e non ci prova.

Il backend Berkeley DB si porta dietro la fragilità di cui sopra: con alta concorrenza, o con processi che muoiono male, la manutenzione del repository è lavoro reale, non un’ipotesi. I branch costano poco a crearsi, ma il merge resta manuale: al rilascio 1.0 non c’è memoria automatica di quali revisioni siano già state fuse, e tenerne il conto tocca a chi gestisce il branch. La copia istantanea è una primitiva solida; riconciliare i rami è ancora mestiere dell’operatore.


Immagine di copertina: Il logo storico di Subversion: il marchio denominativo “subversion” in lettere minuscole — logo di autore sconosciuto, pubblico dominio — https://commons.wikimedia.org/wiki/File:Subversion_logo.svg