This is an in-progress translation.
To help translate the book, please fork the book at GitHub and push your contributions.

I riferimenti di Git

Potete lanciare qualcosa tipo git log 1a410e per vedere tutta la vostra intera history, ma dovete comunque ricordare che quel 1a410e è l’ultima commit per poter essere in grado di percorrere la history stessa per trovare tutti quegli oggetti. Avete bisogno di un file nel quale potete salvare il valore dello SHA-1 attribuendogli un semplice nome in modo da poter usare quel nome al posto del valore SHA-1 grezzo.

In Git, questi sono chiamati “riferimenti” o “refs”; potete trovare i file che contengono i valori SHA-1 nella directory .git/refs. Nel progetto corrente, questa directory non contiene files ma una semplice struttura:

$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
$

Per creare un nuovo riferimento che vi aiuterà a ricordare dov’è la vostra ultima commit, potete tecnicamente fare qualcosa di semplice come questo:

$ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master

Ora potete usare il riferimento appena creato al posto del valore SHA-1 nei vostri comandi Git:

$ git log --pretty=oneline  master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

Non siete incoraggiati ad editare direttamente i file riferimento. Git fornisce un comando sicuro per fare questo se volete agiornare un riferimento, chiamato update-ref:

$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9

Questo è di base cos’è un branch in Git: un semplice puntetore o riferimento alla head di una linea di lavoro. Per creare un branch indietro alla seconda commit, potete fare questo:

$ git update-ref refs/heads/test cac0ca

Il vostro branch conterrà solo il lavoro da quella commit in poi:

$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

Ora, il vostro database Git assomiglia concettualmente all Figura 9-4.


Figura 9-4. La direcotyr degli oggetti Git directory con incluse i riferimenti branch e head.

Quando lanciate comandi come git branch (branchname), Git in pratic lancia il comando update-ref per aggiungere lo SHA-1 dell’ultima commit del branch nel quale siete in qualsiasi nuovo riferimento vogliate creare.

La domanda ora è, quando lanciate git branch (branchname), come fà Git a conoscere lo SHA-1 dell’ultima commit? La risposta è il file HEAD. Il file HEAD è un riferimento simbolico al branch corrente. Con riferimento simbolico intendo che, a differenze di un normale riferimento, non contiente in generale un valore SHA-1 ma piuttosto un puntatore ad unl’altro riferimento. Se esaminate il file, vedrete qualcosa come:

$ cat .git/HEAD 
ref: refs/heads/master

Se lanciate git checkout test, Git aggiorna il file in questo modo:

$ cat .git/HEAD 
ref: refs/heads/test

Quando lanciate git commit, crea l’oggetto commit, specificando che il padre dell’oggetto commit stesso sia il valore SHA-1 al quale punta il riferimento in HEAD.

Potete anche editare manualmente questo file, ma ancora una volta esiste un comando più sicuro per farlo: symbolic-ref. Potete anche leggere il valore della vostra HEAD tramite questo comando:

$ git symbolic-ref HEAD
refs/heads/master

Potet anche impostare il valore di HEAD:

$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD 
ref: refs/heads/test

Non potete impostare un riferimento simbolico al di fuori di refs:

$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/

Tags

Avete appena visto i tre principali tipi di oggetti di Git, ma ce n’è un quarto. L’oggetto tag è molto simile ad un oggetto commit - contiene un tag. una data, un messaggio ed un puntatore. La differenza principale sta nel fatto che un oggetto tag punta ad un oggetto commit piuttosto che ad un albero. E’ come un riferimento ad un branch, ma non si muove - punta sempre alla stessa commit ma gli da un nome più amichevole.

Come discusso nel Capitolo 2, ci sono due tipi di tag: annotated e lightweight. Potete creare un tag lightweight lanciando un comando tipo questo:

$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d

Questo è tutto quello che è un tag lightweight - un branch che non si muove mai. Un tag annotated però è più complesso. Se create un tag annotated, Git crea un oggetto tag e scrive un riferimento al quale puntare, invece di puntare direttamente alla commit. Potete vedere tutto questo creando un tag annotated (-a specifica che si tratta di un tag annotated):

$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 –m 'test tag'

Questo è il valore SHA-1 dell’oggetto creato:

$ cat .git/refs/tags/v1.1 
9585191f37f7b0fb9444f35a9bf50de191beadc2

Ora, lanciando il comando cat-file su questo SHA-1:

$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700

test tag

Notate che l’oggetto punta al valore SHA-1 della commit che avete taggato. Notate anche che non è importante che punti ad un oggetto commit; potete taggare ogni oggetto di Git. Nel codice sorgente di Git, ad esempio, il mantainer ha aggiunto la sua chiave pubblica GPG come oggetto blob e lo ha taggato. Potete vedere la chiave pubblica lanciando

$ git cat-file blob junio-gpg-pub

nel codice sorgente di Git. Anche il kernel di Linux ha un oggetto tag che non punta ad una commit - il primo tag creato punta all’albero iniziale dell’import del codice sorgente.

Remotes

Il terzo tipo di riferimento che vedrete è il riferimento remoto. Se aggiungete un remote e poi fate un push, Git salva il valore del quale avete fatto la push per ogni branch nella directory refs/remotes. Ad esempio potete aggiungere un remote di nome origine fare push del vostro branch master in esso:

$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
   a11bef0..ca82a6d  master -> master

Poi, potete vedere quale era il branch master del remote origin l’ultima volta che avete comunicato con il server, esaminando il file refs/remotes/origin/master:

$ cat .git/refs/remotes/origin/master 
ca82a6dff817ec66f44342007202690a93763949

I riferimenti remoti differiscono dai branch (riferimenti in refs/heads) principalmente per il fatto che non è possibile fare il checkout di quest’ultimi. Git li sposta come segnalibri fino all’ultimo stato conosciuto di quei branch avevano sul server.