Git (software)

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca
Git
software
Logo
Logo
GenereControllo versione
Sviluppatoreinizialmente Linus Torvalds, attualmente Junio Hamano
Data prima versione7 aprile 2005
Ultima versione2.44.0 (23 febbraio 2024)
Sistema operativoGNU/Linux
macOS
Microsoft Windows
Solaris
Linguaggioshell Unix
Python
C++
Tcl
C
Perl
LicenzaGNU GPL v2
(licenza libera)
Sito webgit-scm.com

Git è un software per il controllo di versione distribuito utilizzabile da interfaccia a riga di comando, creato da Linus Torvalds nel 2005.

Git (che nello slang britannico significa idiota[1]) nacque per essere un semplice strumento per facilitare lo sviluppo del kernel Linux ed è diventato uno degli strumenti di controllo versione più diffusi. La sua progettazione si ispirò ad analoghi strumenti, allora proprietari, come BitKeeper e Monotone.

Storia[modifica | modifica wikitesto]

Lo sviluppo di Git è iniziato dopo che molti sviluppatori del kernel di Linux sono stati costretti ad abbandonare l'accesso al codice sorgente tramite il sistema proprietario BitKeeper. La possibilità di utilizzare BitKeeper gratuitamente era stata ritirata dal detentore dei diritti d'autore Larry McVoy dopo avere sostenuto che Andrew Tridgell aveva effettuato il reverse engineering dei protocolli.

Alla conferenza Linux.Conf.Au del 2005, Tridgell dimostrò nel suo intervento che il procedimento di reverse engineering che aveva usato era semplicemente collegarsi con telnet alla porta appropriata di un server Bitkeeper e digitare "help".

Torvalds voleva un sistema distribuito che potesse usare come BitKeeper, ma nessuno dei sistemi disponibili gratuitamente soddisfaceva i suoi bisogni, particolarmente il suo bisogno di velocità. Ecco un messaggio e-mail (tradotto in italiano) che scrisse il 7 aprile 2005 mentre stava scrivendo il primo prototipo:

«Tutti i sistemi di controllo versione che ho preso in considerazione rendono [il lavoro] difficile. Una delle cose (in realtà, la cosa principale) a cui ho lavorato è rendere quel procedimento realmente efficiente. Se ci vuole mezzo minuto per applicare una patch, e ci si deve ricordare i confini delle modifiche applicate, ecc. (e francamente, si potrebbe considerare mezzo minuto poco per la maggior parte dei sistemi di controllo versione che ci sono in giro, e per un progetto della dimensione di Linux), allora una serie di 250 e-mail (che non è affatto inaudito quando mi sincronizzo con Andrew, per esempio) richiede due ore. Neanche BitKeeper si dimostrò rapido (in effetti, confrontato a qualunque altra cosa, BitKeeper è velocissimo, spesso uno o due ordini di grandezza migliore), e richiedeva circa 10–15 secondi per ogni e-mail quando facevo il merge con Andrew. Tuttavia, con BitKeeper quello non era un problema tanto grosso, dato che i merge BitKeeper↔BitKeeper sono più semplici, e non ho mai dovuto fare un più lento merge manuale con gli altri sviluppatori principali.

Perciò il merge, in un sistema di controllo versione basato sull'applicazione di patch dovrebbe essere più veloce di BitKeeper. Il che è veramente difficile. E per questo sto scrivendo alcuni script per tentare di tener traccia delle cose in modo nettamente più veloce.

Le indicazioni iniziali sono che dovrei essere in grado di farlo con la stessa velocità della sola applicazione delle patch. Ma francamente, sono al massimo a metà del lavoro, e se mi imbatterò in qualche ostacolo può darsi che non sarà affatto così. La ragione per cui posso fare questo così velocemente è che i miei script non saranno un sistema di controllo versione, saranno un tipo di cosa molto specifica del tipo “log dello stato di Linus”. Ciò renderà il merge tramite patch molto più veloce, e quindi fattibile.

(Se per applicare una patch ci vogliono tre secondi, anche una lunga serie di patch non è un problema: se vengo avvertito entro uno o due minuti che il merge è fallito a metà strada, va bene, in tal caso posso procedere a correggerlo a mano. Questo è il motivo per cui la latenza è critica — se dovessi fare le cose del tutto “offline”, per definizione non sarei in grado di correggere i problemi quando accadono).»

Linus aveva vari criteri di progettazione:

  1. Prendi CVS come esempio di che cosa non fare; se hai un dubbio, fai l'esatto contrario. Per citare Linus, che parlava un po' ironicamente:
    “Per i primi 10 anni di manutenzione del kernel, usavamo letteralmente tarball (archivi compressi) e patch, che è un sistema di gestione del codice sorgente molto migliore di CVS. Poi ho finito per usare CVS per 7 anni in un'azienda [presumibilmente Transmeta] e lo odio appassionatamente. Quando dico che odio CVS appassionatamente, devo anche dire che se ci sono utenti SVN (Subversion) tra il pubblico, potreste volervene andare. Perché a causa del mio odio di CVS ritengo Subversion il progetto meno sensato che sia mai cominciato. Per un po' lo slogan di Subversion era ‘CVS fatto bene’, o qualcosa di simile, e se incominci con quel tipo di slogan, non puoi andare da nessuna parte. Non c'è modo di fare CVS bene.”
  2. Supporto di un flusso di lavoro distribuito, simile a BitKeeper. Come BitKeeper, Git non usa un server centralizzato.
    “BitKeeper non è solamente il primo sistema di controllo dei sorgenti che abbia mai pensato che valesse la pena usare; è stato anche il sistema che mi ha fatto capire perché ce ne sia effettivamente bisogno, e come si possa operare in modo efficace. Perciò, sebbene da un punto di vista tecnico Git sia molto diverso da BitKeeper (il che era un altro obiettivo di progettazione, perché volevo rendere chiaro che non era un clone di BitKeeper), molti dei procedimenti che usiamo con Git vengono direttamente dai procedimenti che abbiamo imparato da BitKeeper.”
  3. Salvaguardia dalla corruzione dei dati, sia accidentale che intenzionale
  4. Altissime prestazioni

I primi tre criteri non erano soddisfatti da alcun preesistente sistema di controllo versione eccetto Monotone, e il quarto ha escluso anche Monotone. Perciò, immediatamente dopo lo sviluppo della versione 2.6.12-rc2 del kernel di Linux, si è dedicato a scrivere il suo.

Lo sviluppo di Git è cominciato il 3 aprile 2005. Il progetto è stato annunciato il 6 aprile 2005, ed è stato usato per gestire il proprio sorgente a partire dal 7 aprile 2005. La prima fusione di più branch in uno è stata fatta il 18 aprile 2005. Torvalds ha raggiunto i suoi obiettivi in termini di prestazioni: il 29 aprile 2005, Git riusciva ad applicare 6 o 7 patch a Linux in un secondo. Il 16 giugno 2005 è stata pubblicata la versione 2.6.12 del kernel di Linux, la prima gestita con Git.

Sebbene fortemente influenzato da BitKeeper, Torvalds ha deliberatamente tentato di evitare approcci convenzionali, il che ha prodotto un sistema molto innovativo.

Torvalds ha sviluppato il sistema fino a quando è diventato usabile da utenti tecnici; poi, il 26 luglio 2005, ha ceduto la manutenzione a Junio Hamano, un importante contributore al progetto. Hamano è stato il responsabile della versione 1.0, pubblicata il 21 dicembre 2005, e rimane oggi il manutentore.

Descrizione[modifica | modifica wikitesto]

Caratteristiche[modifica | modifica wikitesto]

Il progetto di Git è la sintesi dell'esperienza di Torvalds nel mantenere un grande progetto di sviluppo distribuito, della sua intima conoscenza delle prestazioni del file system, e di un bisogno urgente di produrre un sistema soddisfacente in poco tempo. Queste influenze hanno condotto alle seguenti scelte implementative:

  • Forte supporto allo sviluppo non lineare. Git supporta diramazione e fusione (branching and merging) rapide e comode, e comprende strumenti specifici per visualizzare e navigare una cronologia di sviluppo non lineare. Un'assunzione centrale in Git è che una modifica verrà fusa più spesso di quanto sia scritta, dato che viene passata per le mani di vari revisori. Torvalds stesso fa la maggior parte delle fusioni e una piccola parte delle correzioni dirette al codice, perciò egli stesso ha dimostrato che questo aspetto funziona bene.
  • Sviluppo distribuito. Similmente a Bazaar, Darcs, BitKeeper, Mercurial, SVK, e Monotone, Git dà a ogni sviluppatore una copia locale dell'intera cronologia di sviluppo, e le modifiche vengono copiate da un tale repository a un altro. Queste modifiche vengono importate come diramazioni aggiuntive di sviluppo, e possono essere fuse allo stesso modo di una diramazione sviluppata localmente.
  • I repository possono essere pubblicati facilmente tramite HTTP, FTP, ssh, rsync, o uno speciale protocollo git. Git ha anche un'emulazione del server CVS, che consente di usare gli esistenti client CVS e plugin per IDE per accedere ai repository Git.
  • Gestione efficiente di grandi progetti. Git è molto veloce e scalabile. È tipicamente un ordine di grandezza più veloce degli altri sistemi di controllo versione, e due ordini di grandezza più veloce per alcune operazioni[2].
  • Autenticazione crittografica della cronologia. La cronologia di Git viene memorizzata in modo tale che il nome di una revisione particolare (secondo la terminologia Git, una "commit") dipende dalla completa cronologia di sviluppo che conduce a tale commit. Una volta che è stata pubblicata, non è più possibile cambiare le vecchie versioni senza che ciò venga notato. (Anche Monotone ha questa proprietà.)
  • Progettazione del toolkit. Git è un insieme di programmi di base scritti in linguaggio C, e molti script di shell che forniscono comodi incapsulamenti. È facile concatenare i componenti per fare altre cose utili.
  • Strategie di fusione intercambiabili. Come parte della progettazione del suo toolkit, Git ha un modello ben definito di una fusione incompleta, e ha più algoritmi per tentare di completarla. Se tutti gli algoritmi falliscono, tale fallimento viene comunicato all'utente e viene sollecitata una fusione manuale. Pertanto è facile sperimentare con nuovi algoritmi di fusione.
  • La spazzatura si accumula fino a quando viene raccolta. Quando si abortisce un comando o si scartano delle modifiche si lasciano degli oggetti inutilizzabili nel database. Tipicamente, questi sono solo una piccola parte della cronologia continuamente crescente degli oggetti utili, ma il comando di recupero dello spazio, git gc --prune, può richiedere parecchio tempo.

Una proprietà di Git che ha prodotto considerevoli controversie è il fatto che prende istantanee di interi alberi di directory di file invece che di singoli file. I primi sistemi di controllo versione del codice sorgente, SCCS and RCS, lavoravano su singoli file, e vantavano il risparmio di spazio ottenibile dalla codifica delta delle versioni simili. I successivi sistemi di controllo versione mantennero questo concetto di identità dei file al variare delle revisioni di un progetto.

Git rifiuta questo concetto e non registra esplicitamente le relazioni di revisione di file a nessun livello all'interno dell'albero del codice sorgente. Ciò comporta conseguenze rilevanti:

  • È effettivamente leggermente più costoso esaminare la cronologia di modifiche di un singolo file rispetto a quella dell'intero progetto. Per ottenere la cronologia delle modifiche che riguardano un dato file, Git deve ripercorrere la cronologia complessiva e poi determinare quali modifiche hanno riguardato quel file. Questo metodo di esaminare la cronologia, comunque, permette a Git di produrre con altrettanta efficienza una singola cronologia che mostra le modifiche a un arbitrario insieme di file. Per esempio, una sottodirectory dell'albero dei sorgenti più un file di intestazione (header) globale a loro associato.
  • I cambiamenti di nome di file e directory vengono gestiti in modo implicito invece che esplicito. Una grossa lamentela degli utenti di CVS è che usa il nome di un file per identificare la sua cronologia di revisioni, perciò non è possibile spostare un file o cambiargli nome senza interrompere la sua cronologia, così come cambiare nome alla cronologia rendendola inaccurata. La maggior parte dei sistemi di controllo versioni successivi a CVS risolvono questo problema dando a ogni file un nome interno univoco di lunga vita che sopravvive al cambiamento di nome. Git non memorizza un identificatore di questo genere, e questo viene descritto come un vantaggio. I file di codice sorgente vengono talvolta spezzati o fusi oltre che semplicemente cambiati di nome, e memorizzare tali modifiche come un semplice cambiamento di nome congelerebbe per sempre nella cronologia una descrizione inaccurata di quello che è successo. Git affronta la questione rilevando i cambiamenti di nome mentre sfoglia la cronologia delle istantanee invece di memorizzarli quando si prende un'istantanea. (In breve, dato un file alla revisione N, un file con lo stesso nome alla revisione N-1 è il suo antenato di default. Tuttavia, quando non ci sono file dal nome simile alla versione N-1, Git cerca un file che esisteva solamente alla versione N-1 e che abbia un contenuto molto simile a quello del nuovo file.) Questo richiede più lavoro di CPU ogni volta che si esamina la cronologia, e alcune opzioni per calibrare l'euristica.

Inoltre, gli utenti talvolta sono turbati dal modello di immagazzinamento:

  • Impacchettamento esplicito periodico degli oggetti. Git immagazzina ogni nuovo oggetto in un file distinto.

Sebbene tale file sia in un formato compresso, può occupare parecchio spazio ed essere inefficiente. Questo problema è risolto dall'uso di "impacchettamenti" ("packs") che immagazzinano molti oggetti in un solo file (o in un flusso di dati via rete), che hanno essi stessi una compressione delta. Gli impacchettamenti vengono compressi con l'euristica che i file con lo stesso nome sono probabilmente simili, funzionano correttamente anche se questa supposizione non è valida. Gli oggetti appena creati (cioè appena aggiunti alla cronologia) sono ancora immagazzinati singolarmente, e per mantenere l'efficienza si dovrebbe effettuare periodicamente un impacchettamento.

Git implementa varie strategie di fusione; in fase di fusione si può scegliere un comportamento diverso da quello di default:

  • risolvi (resolve): Questo è l'algoritmo tradizionale di fusione a 3 vie.
  • ricorsivo (recursive): Questo è l'algoritmo di default quando si estrae o si fonde un ramo, ed è una variante dell'algoritmo di fusione a 3 vie. "Quando ci sono più antenati comuni che possono esser usati per una fusione a 3 vie, crea un albero di fusione degli antenati comuni e lo utilizza come albero di riferimento per la fusione a 3 vie. Questo risulta produrre meno conflitti di fusione senza provocare mal-fusioni dalle prove effettuate su effettive fusioni di rilascio prese dalla cronologia di sviluppo del kernel Linux 2.6. Inoltre, questo può rivelare e gestire i cambiamenti di nome."
  • piovra (octopus): questo è l'algoritmo di default quando si fondono più di due teste.

Implementazione[modifica | modifica wikitesto]

Le primitive di Git non costituiscono inerentemente un sistema di controllo della versione. Per esempio, git non fornisce una numerazione progressiva delle revisioni del software.

Torvalds spiega che,

«in molti modi si può considerare git come un filesystem — è indirizzabile in base al contenuto, e include il concetto di versione, ma io in realtà l'ho progettato guardando il problema dal punto di vista di una persona esperta di filesystem (beh, i kernel sono quello che faccio), e effettivamente ho assolutamente zero interesse nel creare un sistema tradizionale di gestione della configurazione software.»

(Si noti che in seguito la sua opinione è cambiata.)

Git ha due strutture dati, un indice modificabile che mantiene le informazioni sul contenuto della prossima revisione, e un database di oggetti a cui si può solo aggiungere e che contiene quattro tipi di oggetti:

  • Un oggetto blob è il contenuto di un file. Gli oggetti blob non hanno nome, data, ora, né altri metadati. Git memorizza ogni revisione di un file come un oggetto blob distinto.
  • Un oggetto albero è l'equivalente di una directory: contiene una lista di nomi di file, ognuno con alcuni bit di tipo e il nome di un oggetto blob o albero che è il file, il link simbolico, o il contenuto di directory. Questo oggetto descrive un'istantanea dell'albero dei sorgenti.
  • Un oggetto commit (revisione) collega gli oggetti albero in una cronologia. Contiene il nome di un oggetto albero (della directory dei sorgenti di livello più alto), data e ora, un messaggio di archiviazione (log message), e i nomi di zero o più oggetti di commit genitori. Le relazioni tra i blob si possono trovare esaminando gli oggetti albero e gli oggetti commit.
  • Un oggetto tag (etichetta) è un contenitore che contiene riferimenti a un altro oggetto, può tenere metadati aggiuntivi riferiti a un altro oggetto. Il suo uso più comune è memorizzare una firma digitale di un oggetto commit corrispondente a un particolare rilascio dei dati gestiti da Git.

I blob sono file binari "non parlanti" che conservano informazioni eterogenee, quali: file testuali o binari, immagini, codice sorgente, archivi. Qualsiasi tipo di file è compresso in un file binario prima di essere salvato in repository Git. Git ne calcola l'hash con l'algoritmo SHA-1.
L'hash è una sequenza di 40 caratteri alfanumerici, che rappresentano un numero esadecimale, ed è utilizzato da Git per identificare in modo univoco qualsiasi commit nel repository, tracciando il file al suo interno e le eventuali modifiche effettuate. L'hash SHA-1 di un oggetto è unico, risultando lo stesso a prescindere dal repository e dal computer utilizzato. Git calcola tale codice hash, e usa questo codice come nome dell'oggetto e come identificatore del suo contenuto: file con nomi e/o percorsi diversi, ma con identico contenuto (blob), condividono lo stesso hash.[3]

L'indice è uno strato intermedio che serve da punto di collegamento fra il database di oggetti e l'albero di lavoro.

Il database ha una struttura semplice. L'oggetto viene messo in una directory che corrisponde ai primi due caratteri del suo codice hash; Il resto del codice costituisce il nome del file che contiene tale oggetto. Quando si aggiunge un nuovo oggetto, questo viene memorizzato per intero dopo averlo compresso con zlib.

Questo fatto può far sì che in poco tempo venga occupato molto spazio sul disco fisso, perciò gli oggetti possono essere combinati in pack, che usano la compressione delta (memorizzando solo le modifiche tra un blob e un altro blob) per risparmiare spazio.


Portabilità[modifica | modifica wikitesto]

Git è pensato per funzionare in tutti i sistemi operativi basati su GNU/Linux, ma funziona anche in altri sistemi unix-like, tra cui BSD, Solaris e Darwin. Git è estremamente veloce su sistemi basati su POSIX come i suddetti.

Git può essere portato anche in ambiente Windows. Ci sono in effetti due possibilità per farlo: quella "ufficiale" richiede di installare e usare l'ambiente Cygwin (che è una emulazione POSIX); l'alternativa è un port nativo, cioè una modifica del codice sorgente per adattarlo a Windows. Git su Windows è sensibilmente più lento, a causa del massiccio uso da parte di Git di funzionalità POSIX del file system che devono essere emulate in ambiente Windows. Inoltre, molta gente trova che l'installazione di Cygwin sia troppo grande e invasiva per un tipico utente di Windows.

Esistono molti progetti open source che per ora hanno esplicitamente rinunciato a usare Git a causa della sua poca compatibilità con Windows, tra cui Mozilla e Ruby.

Un port nativo per Windows, con il nome di "WinGit" divenuto poi "Git on MSys", si avvicina al completamento utilizzando il compilatore MinGW.

In alcuni casi (particolarmente per l'accesso remoto anonimo), si possono ammettere gli utenti Windows tramite il git-cvsserver (che emula un server CVS, consentendo l'uso di client CVS per Windows). Altre alternative sono:

  • Un client GIT basato su EclipseIDE, che usa un'implementazione in puro Java delle funzioni interne di GIT
  • Un'estensione di Windows Explorer basata su libgit + cygwin.dll (è già iniziato un progetto per un software simile a TortoiseCVS)

Incapsulare in una libreria le operazioni di git a livello più basso in teoria consentirebbe la re-implementazione delle componenti di livello più basso per Windows senza dover riscrivere il resto.

Questi sforzi in generale dovrebbero aiutare a migliorare le prestazioni e la facilità di installazione su Windows; non è chiaro però se aiuteranno a risolvere la questione dei diversi modelli di autorizzazione.

Progetti correlati[modifica | modifica wikitesto]

Progetti che si basano su Git[modifica | modifica wikitesto]

  • git-gui è una GUI basata su Tk per le operazioni più comuni di Git. Questo progetto è incorporato in Git versione 1.5.0 e successive. (Si lancia con il comando "git gui").
  • Cogito - Petr Baudiš ha mantenuto un insieme di script chiamato Cogito (precedentemente git-pasky), che formano un sistema di controllo versione che usa Git come backend[4]. Lo sviluppo di Cogito è stato interrotto nell'aprile 2007 quando la sua funzionalità è stata ritenuta ridondante con gli strumenti di frontend di Git, comunemente chiamati "porcellana" ("porcelain").
  • StGIT - Stacked GIT è un'applicazione Python che fornisce funzionalità simili a Quilt[5] (cioè aggiungere/togliere patch a/da uno stack) appoggiandosi a Git, per gestire le patch fino a quando vengono fuse[6].
  • Patchy GIT è un'interfaccia a Git costituita da script di shell per aiutare l'utente a gestire un insieme di patch ai file. pg è in un certo senso simile a Quilt o a StGIT, ma ha un insieme di caratteristiche leggermente diverso. pg non viene più mantenuto dal 29 aprile, 2007
  • DarcsGit - un'estensione di Darcs che gli consente di interagire con i repositori Git[7].
  • bzr-git - un plugin per Bazaar per leggere gli alberi di Git[8]. Sebbene sia ancora in fase alpha, fornisce abbastanza supporto per bzrk.

Interfacce Web[modifica | modifica wikitesto]

  • Gogs: Un frontend git con gestione degli utenti, delle segnalazioni, dei fork e molte altre funzionalità, scritto in go[9].
  • Gitea: Un fork comunitario di Gogs[10].
  • gitweb – un'implementazione in Perl mantenuta da Kay Sievers[11]. Usata dal sito kernel.org
  • wit – un'implementazione Python mantenuta da Christian Meder[12].
  • gitarella – un'implementazione Ruby mantenuta da Diego Elio Pettenò[13]
  • git-php – un'implementazione PHP di Zack Bartel[14]
  • cgit - un'implementazione C di Lars Hjemli[15]
  • Bitbucket usa i sistemi di controllo versione Git dall'ottobre 2011.

Visualizzazione della cronologia[modifica | modifica wikitesto]

  • Gitk è una semplice GUI Tcl/Tk per consultare facilmente la cronologia dei repository Git, distribuita con Git[16].
  • QGit è una GUI Qt per consultare la cronologia dei repository, simile a Gitk[17].
  • Giggle è una GUI GTK+ ispirata da Gitk[18].
  • gitview è una GUI Python e Gtk+, distribuita con Git.
  • tig è un'interfaccia testuale a pieno schermo basata su ncurses per Git".
  • git-browser è un programma di consultazione della cronologia scritto in JavaScript che è utilizzabile in un browser web. (Pare che non consenta di esaminare le modifiche al codice, ma solo le descrizioni.)

Note[modifica | modifica wikitesto]

  1. ^ Significato di git, su wordreference.com. URL consultato il 9 giugno 2016.
  2. ^ Roland Dreier, Oh what a relief it is, su digitalvampire.org, 13 novembre 2006., observing that "git log" is 100x faster than "svn log" because the latter has to contact a remote server.
  3. ^ Ferdinando Santacroce, Git: Guida per imparare a gestire, distribuire e versionare codice, Milano, Apogeo, 2017, pp. 47, 52-53, ISBN 9788850334759, OCLC 1065376849. URL consultato il 10 luglio 2019 (archiviato il 10 luglio 2019).
  4. ^ homepage
  5. ^ homepage
  6. ^ homepage
  7. ^ Copia archiviata, su wiki.darcs.net. URL consultato il 29 settembre 2007 (archiviato dall'url originale il 29 settembre 2007).
  8. ^ bzr-git
  9. ^ Gogs
  10. ^ Gitea
  11. ^ gitweb[collegamento interrotto]
  12. ^ wit Archiviato il 19 gennaio 2008 in Internet Archive.
  13. ^ gitarella
  14. ^ git-php
  15. ^ cgit
  16. ^ Gitk
  17. ^ QGit
  18. ^ Giggle

Voci correlate[modifica | modifica wikitesto]

Altri progetti[modifica | modifica wikitesto]

Collegamenti esterni[modifica | modifica wikitesto]

Controllo di autoritàVIAF (EN304416640 · LCCN (ENn2013035657 · GND (DE7687494-1 · BNF (FRcb17031353d (data) · J9U (ENHE987007365079405171