Git è oggi il sistema di controllo di versione più conosciuto al mondo. Partorito dalla mente del creatore del kernel Linux, Linus Torvalds, con lo scopo di rendere più agevole la gestione proprio dei sorgenti di Linux, si è diffuso al punto da divenire lo standard de-facto quando si parla di VCS (Version Control System). Ha addirittura favorito la nascita di servizi di successo come Bitbucket (circa 6 milioni di utenti nel 2018), Github (circa 31 milioni di utenti a novembre 2018), Gitlab e molti altri, creati appunto attorno alle funzionalità di Git.
Su HTML.it è disponibile una guida dettagliata a Git, in cui è possibile trovare informazioni sul funzionamento di questo VCS.
Alcune caratteristiche differenziano significativamente Git da altri VCS. In primo luogo, la sua architettura distribuita permette a ciascun utente di possedere una copia intera del database di versione. Ciò consente di lavorare sul repository senza richiedere una connessione ad Internet e senza dover caricare di lavoro un server dedicato.
Da un punto di vista tecnico, la caratteristica di maggior rilievo è sicuramente la struttura dati utilizzata per gestire il database delle versioni: il vero e proprio cuore di git. Questa struttura è molto efficiente in quanto sfrutta tecniche di de-duplicazione, compressione, codifica delta, con lo scopo di ridurre al minimo l'overhead su disco. Poichè il database è distribuito infatti, su ogni workstation vi è spazio occupato sia dai file del repository (ad esempio, i sorgenti) sia dal database (che costituisce overhead).
Oltre ad essere efficiente, si tratta di un formato generico, in grado di accogliere qualunque tipo di dato. Sebbene Git sia un VCS, e nasca quindi con lo scopo di gestire repository di sorgenti, esso è stato progettato per non dipendere in particolare da alcun linguaggio, formato o struttura. Un repository è, per Git, una semplice porzione di file system, con le sue directory ed i suo file. Come indicato dagli stessi autori, Git è semplicemente un file system content-addressable, ovvero una struttura dati gerarchica i cui oggetti sono accessibili mediante una chiave.
Questa caratteristica ha favorito l'impiego di Git in ambiti che esulano dal controllo di versione, talvolta in modo piuttosto creativo. Di seguito ne riportiamo alcuni.
Backup
Un side effect abbastanza ovvio nell'utilizzo di Git è la disponibilità di copie di backup del repository. Ogni workstation che effettua un clone del repository possiede una copia completa dello stesso e del database contenente tutte le versioni precedenti.
Poiché Git può gestire qualunque tipo di file, inclusi file di grandi dimensioni (grazie all'opzione LFS), è sufficiente creare un repository per la directory della quale effettuare il backup ed invocare i comandi commit e push per trasmettere una copia ad uno o più server remoti.
Deploy di siti
Analogamente al caso del backup, la funzionalità di push su server remoto può essere sfruttata per effettuare degli upload. Sono molti i servizi di hosting web ad esempio che offrono questa modalità come alternativa all'uso del vetusto FTP. I vantaggi sono molteplici: i push vengono effettuati solo da utenti accreditati, il trasferimento dati è cifrato ed è possibile ripristinare una versione precedente del sito semplicemente con un comando, in caso di errori.
Archiviazione e compressione
Come già detto, Git è molto efficiente nella memorizzazione. Grazie al comando bundle è possibile creare un archivio compresso contenente tutti i dati del repository. I file bundle possono essere "estratti" utilizzando il comando unbundle.
Rispetto ad un metodo di archiviazione tradizionale, i file bundle contengono oltre ai file nelle loro versioni attuali anche i dati relativi alle versioni precedenti. Se non si vuole esportare l'intera storia del repository, è possibili limitare il numero di versioni da salvare nel bundle con lo switch --since
.
Database NoSQL
Esistono diversi tipi di database NoSQL che si differenziano in base alle strutture dati che utilizzano: chiave-valore, documenti, grafi, ecc. Poichè, Git è essenzialmente un archivio chiave-valore, è possibile utilizzarlo come database NoSQL.
A tal proposito, è possibile interagire direttamente con il database Git, senza dover necessariamente creare dei file nella directory del repository. Ciò è possibile invocando comandi di basso livello noti come "plumbing commands". I comandi di uso comune come init
, add
, commit
, ecc. sono detti invece "porcelain commands". Ciascun porcelain command esegue di fatto una serie di plumbing commands, in base al caso specificio.
Ad esempio, il plumbing command hash-object consente di memorizzare nel database Git un valore (di qualunque natura) e ne restituisce la chiave corrispondente. Il valore può essere fornito direttamente dallo standard input:
# echo "Il valore da memorizzare" | git hash-object -w --stdin
Lo switch -w
indica di voler memorizzare il valore e lo switch --stdin
indica che l'input verrà letto dallo standard input del comando (in questo caso, l'output del comando echo).
Il comando restituisce in output la chiave associata da git la valore: nell'esempio, fec21c728b04cccf4c03f339525e25a5d5d19fbc
.
Per interrogare il database, si utilizza invece il comando
# git cat-file -p fec21c728b04cccf4c03f339525e25a5d5d19fbc
Restituisce il valore precedentemente memorizzato, ovvero la stringa Il valore da memorizzare.
L'implementazione delle funzionalità sopra descritte è contenuta nella libreria libgit2, per la quale esistono dei bindings per diversi linguaggi di programmazione. Ciò permette di sfruttare Git come database chiave-valore nei propri programmi senza utilizzare la riga di comando.
Maggiori dettagli sulla struttura del database git e sui comandi di plumbing sono disponibili nella documentazione ufficiale.
Conclusioni
Gli esempi riportati sopra dimostrano ancora una volta come la creazione di software aderente alla filosofia Unix ("Scrivere programmi che facciano una cosa sola e bene. Scrivere programmi che lavorino insieme. Scrivere programmi che possano elaborare flussi di testo, perché questa è un'interfaccia universale") permetta di sviluppare strumenti in grado di superare lo scopo per cui sono stati originariamente concepiti.
La modularità e l'apertura di Git lo rendono uno strumento versatile e potente pur rimanendo di semplice utilizzo ed alla portata di tutti.