Primi passi con Git

23/11/2025

Non solo per sviluppatori

Git nasce dalla mente di Linus Torvalds (si, proprio quello di Linux!) come un sistema di controllo di versione distribuito, nell'ambito della programmazione software.
Pensato per agevolare lo sviluppo del kernel Linux, Git si è imposto come lo standard de facto per la distribuzione del codice sorgente delle applicazioni open source.

Tra i suoi punti di forza l'impostazione collaborativa priva di un server centrale protagonista, oltre alla grande flessibilità con cui è possibile operare su più copie dello stesso codice.
Simili caratteristiche rendono tuttavia Git adatto anche a contesti differenti rispetto a quello nativo. Potenzialmente qualsiasi tipo di progetto pensato per essere monitorato ed evolvere nel tempo può giovare delle peculiarità di Git.

La magia del plain text

Uno dei principali limiti di Git è quello di non essere adatto all'impiego con file di grandi dimensioni.
Un difetto che in realtà quasi obbliga all'uso virtuoso di testo semplice, o plain text.
Parlo di virtuosità in quanto questi file sono trasparenti e tendenzialmente facili da interpretare, sia dagli umani che dalle macchine.
Al contrario dei file binari, il loro contenuto è composto effettivamente dal testo al loro interno, in quanto non generati da processi come la compilazione.

Linguaggi quali JSON (in realtà un formato basato su un linguaggio) o Markdown rendono ancora più interessante l'impiego del plain text, che sarà poi elaborato automaticamente per usi più specifici.
I file testuali, inoltre, sono generalmente degli "standard by design", quindi facilmente interoperabili tra hardware e software eterogenei.

Per consuetudine la rappresentazione dei comandi avviene con il prefisso "$ ", che non va digitato nella shell.
Il contenuto preceduto da "#" rappresenta un commento esplicativo.

Installazione

Git è un pacchetto molto leggero e reperibile per qualsiasi distro. Di seguito esempi per l'installazione sulle principali distribuzioni.
$ sudo apt install git   # Debian e derivate $ sudo dnf install git   # Fedora e derivate $ sudo pacman -S git   # Arch e derivate

Repository

Una volta installato il necessario, si può procedere alla creazione di una repository. Si tratta della cartella radice di un progetto sviluppato con Git. Ogni directory, che sia vuota o meno, può essere convertita in una repo digitando: $ git init Il comando soprastante procederà alla creazione della directory nascosta .git, già popolata con tutto l'indispensabile. Di fatto, quindi, una repository Git consiste in una normale cartella (detta albero di lavoro) che contiene al suo interno la directory git.

Tracciamento di nuovi file

Adesso poniamo di creare alcuni file: $ touch file1 file2 Otterremo una piccola gerarchia rappresentabile come: radice/
 |--.git/
 |--file1
 |--file2

Il file1 e il file2, però, non sono ancora tracciati da Git, che non deve obbligatoriamente tenere conto dell'intero contenuto dell'albero di lavoro. Un comando farà un po' di chiarezza sulla situazione corrente: $ git status Ci verrà restituito, tra le altre cose, in output: File non tracciati:
 file1
 file2
Il software si è accorto che ci sono nuovi file all'interno dell'albero di lavoro, ma attende la nostra autorizzazione per poterli processare. Qui abbiamo due possibilità per agire: $ git add file1 file2   # File aggiunti a mano, anche parziali
$ git add .   # Tutti i file dell'albero di lavoro Ora git status mostrerà: Modifiche di cui verrà eseguito il commit:
 nuovo file: file1
 nuovo file: file2

I file aggiunti (tracciati) nelle loro varie versioni vengono "copiati" all'interno della directory git. Non è proprio così immediato, ma, semplificando, ogni file viene compresso e convertito in binario per essere archiviato. In questo modo, a partire da una directory git è sempre possibile ricreare i file originali dell'albero di lavoro.

Commit

In Git un commit è assimilabile alla definizione di uno snapshot: un'instanea dell'albero di lavoro in un dato momento.
Eseguiamo quindi il primo commit dei file aggiunti in precedenza: $ git commit -m "Primo commit"   # Il messaggio del commit è arbitrario Il commit verrà creato assieme ad un codice identificativo, l'autore, il timestamp (data e ora), il messaggio descrittivo ed i file coinvolti.

Tracciamento delle modifiche

Cosa accade invece se file già tracciati vengono modificati? Qui subentra un nuova "zona grigia", cioè l'area di staging.
Le modifiche apportate, per non essere ignorate da Git, andranno preventivamente aggiunte nell'area di staging, ossia preparate per diventare parte di un commit.
Anche in questo caso ci si dovrebbe avvalere di git add, ma in assenza di nuovi file si può inglobare direttamente in git commit con l'opzione -a: $ git commit -am "Messaggio di commit" Automaticamente tutte le modifiche ai file già tracciati verrano portate nell'area di staging e "committate".

Un comando per domarli

Volendo essere pignoli, anche i nuovi file alla loro prima comparsa costituiscono una modifica, finendo nell'area di staging, pronti per il commit.
Per andare sul sicuro, comunque, ed evitare inutile confusione qualora le esigenze non richiedano ulteriore granularità (nella maggior parte dei casi), git add . è la panacea per tutti i mali nel tracciamento di Git. Impartito prima di ogni commit evita di lasciarsi alle spalle file fantasma o modifiche non dichiarate, rendendo pure superflua l'opzione -a .
Tutti i comandi illustrati finora si possono applicare anche per intere cartelle, invece che sui singoli file.

Branch

In assenza di modifiche o novità, git status esporrà un output quasi del tutto vuoto: Sul branch master non c'è nulla di cui eseguire il commit, l'albero di lavoro è pulito. Il branch master? L'attuale ramo di sviluppo, in realtà sempre menzionato da git status.
Il ramo master (a volte chiamato main) può nascere e morire in completa solitudine, ma durante il suo cammino ha la possibilità di essere affiancato da altri branch.
I commit non sono legati in modo indissolubile ad un branch, quanto più alla situazione dell'albero di lavoro in un preciso istante.
Anche al di fuori della programmazione, agire sui branch significa poter lavorare su un numero arbitrario di versioni dell'albero di lavoro (attenzione, qui intendo un concetto diverso da quello della versione di un software).
Se avete in mente di attuare modifiche rilevanti al vostro progetto, ma allo stesso tempo non volete azzardarvi a toccare l'archivio creato finora, il branch è lo strumento giusto per voi.

A partire da un commit, e mentre siamo ancora in master, possiamo creare un nuovo ramo: $ git switch -c modifiche_pericolose Se apparentemente sembrerà non essere cambiato nulla, in realtà saremo catapultati all'interno del nuovo ramo, ancora del tutto identico a quello principale.

Un comando ci verrà in aiuto: $ git branch -v Un output del tutto simile a questo (ponendo di aver effettuato solo un commit sul ramo master) ci mostrerà: *modifche_pericolose [codice] Primo commit
 main [codice] Primo commit
Dunque: noi siamo sul branch evidenziato dall'asterisco, ma stiamo ancora condividendo lo stesso commit, e di conseguenza il medesimo albero di lavoro.

Bene, ora concateniamo i comandi visti in precedenza, committando un nuovo file e verificando la situazione dei branch: $ touch file3 && git add . && git commit -m "Secondo commit" && git branch -v Avremo in risposta: *modifche_pericolose [codice] Secondo commit
 main [codice] Primo commit
Sul branch attuale ci sono ora delle modifiche più recenti, immortalate nel secondo commit.

Merge

Apprestiamoci a tornare nel ramo master (stavolta l'opzione -c di create non sarà necessaria): $ git switch master Ci accorgeremo presto che il file3 sarà sparito dalla circolazione, in quanto ancora confinato al branch modifiche_pericolose. Il comando switch, infatti, è in grado di modificare instantaneamente il contenuto della cartella di lavoro a seconda del ramo in cui ci muoviamo.

Come inglobare le modifiche del secondo ramo in quello master? Con il comando git merge: $ git merge modifiche_pericolose Git branch -v ci aggiornerà con: *modifche_pericolose [codice] Secondo commit
main [codice] Secondo commit
Ok, questa è la situazione più lineare possibile, in quanto per allineare i branch è sufficiente portare il ramo master al secondo commit. Se ci fossero stati conflitti o modifiche nel ramo principale prima del merge, le cose non sarebbero state così semplici.

A merge effettuato, generalmente i branch secondari vengono eliminati con: $ git branch -d modifiche_pericolose

Perché abbiamo usato git branch per eliminare un ramo, ma git switch per crearlo?
Trovo più lineare agire in questo modo, in quanto git switch può agevolmente occuparsi sia della creazione che dello spostamento tra i branch.
Naturalmente è possibile anche ricorrere a git branch per aggiungere un nuovo ramo.

Ricapitolando

Dopo aver inizializzato una repository all'interno di una cartella con git init, si può procedere alla creazione di nuovi file e aggiungerli al tracciamento di Git con git add. Ogni volta che si opera sui file è indispensabile ricorrere allo stesso comando.
Git commit "scatterà una fotografia" del vostro albero di lavoro.
Git switch permetterà di creare delle vere e proprie diramazioni, gestendo dei branch paralleli.
Git merge infine, sarà utile per portare le modifiche effettuate nei rami aggiuntivi in quello master.
Git status e git branch torneranno utili per tenere la situazione sotto controllo.

Muoversi nel tempo e nello spazio

Alcuni paragonano Git ad una macchina del tempo, e non a torto.
Ci si può spostare agevolmente tra i commit, ripristinando ogni volta la struttura dell'albero di lavoro memorizzata al loro interno.
Lavorando su più rami, invece e un po' come muoversi nello spazio.
Git è tutto questo, e molto altro.

[user@dajelinux ~]$ dajelinux -wtf

Hai notato qualche errore?
Pensi che sia stato poco chiaro, magari dando per scontato un termine o un concetto che non riesci a capire?
Vuoi proporre un approccio differente all'argomento?
Contattami per feedback e chiarimenti, l'open source è anche questo!