back to top

I comandi git status, git log, git blame e git diff

Nelle lezioni precedenti abbiamo visto come funziona Git internamente e abbiamo iniziato a usare alcuni dei comandi messi a disposizione. Man mano che si lavora a un progetto e cresce il numero di commit creati, nasce la necessità di avere a diposizione degli strumenti per visualizzare e analizzare lo stato corrente o passato del repository, della Staging Area e della Working area.

In questa lezione illustreremo alcuni dei comandi che è possibile utilizzare a tal proposito. Dato il gran numero di opzioni che ogni comando mette a disposizione, è comunque consigliabile leggere la documentazione ufficiale. (git help <nome-comando>)

Visualizzare lo stato corrente della Working Directory con git status

Partiamo con uno dei comandi che abbiamo già ampiamente usato nei precedenti articoli, ovvero git status che consente di visualizzare lo stato corrente della Working Area e vedere, per esempio, quali file sono nella Staging Area, pronti per essere inseriti nel prossimo commit. L’esempio che segue mostra l’output del comando git status lanciato all’interno di una cartella in cui sono presenti 3 file: il file1.txt è nello stato ‘Untracked’ mentre il file2.txt è stato aggiunto alla staging area con il comando git add così come il file3.txt che però è stato in parte modificato.

$ touch file1.txt file2.txt file3.txt
$ git add file2.txt file3.txt
$ echo ciao > file3.txt
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

  new file:   file2.txt
  new file:   file3.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   file3.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

  file1

Mostrare i commit del repository con git log

Un altro interessante comando è git log che mostra l’elenco dei commit presenti nel repository. Presenta un gran numero di opzioni utili che consentono di elencare e filtrare i commit in base a determinati parametri specificati. Grazie al comando git log possiamo avere un’idea chiara dello stato corrente del repository e informazioni utili riguardo ciascun commit in esso contenuto.

Eseguendo semplicemente git log verrà mostrato l’elenco dei commit presenti nel repository che sono raggiungibili a partire dal commit corrente.

visualizzare i commit presenti nel repository con git log

Anche se parleremo in maniera approfondita dei branch a partire dalla prossima lezione, ricordiamo che un branch è semplicemente un riferimento a un commit. Grazie ai branch è possibile avere uno sviluppo non lineare del progetto e quindi avere dei commit che non appartengono a un branch. Facendo riferimento all’immagine in alto, se eseguiamo il comando git log a partire dal commit corrente (nell’immagine il commit corrente è quello blu) verranno mostrate delle informazioni sui commit inclusi all’interno del rettangolo arancione. Riprendiamo l’esempio visto nella quarta lezione di questa guida e lanciamo il comando git log.

[ test_git_repo ] (master) $ tree
.
├── file_0.txt
├── file_1.txt
└── folder
    ├── file_1.txt
    └── file_2.txt

1 directory, 4 files

[ test_git_repo ] (master) $ git log
commit 562980633630afe3b9f55ed26e97ce466dda3953
Author: Claudio M <claudio@example.com>
Date:   Wed Dec 13 17:34:51 2017 +0000

  Aggiunge il file_0.txt e aggiorna file_1.txt


commit c6048756ff5cbb61bfabb6f95d1c559d9dbbf768
Author: Claudio M <claudio@example.com>
Date:   Wed Dec 13 17:17:17 2017 +0000

  first commit

Il comando git log mostra i commit in ordine cronologico inverso. È possibile mostrarli in ordine crescente con l’opzione –reverse.

Si possono usare diverse opzioni con il comando git log. Per esempio con l’opzione –pretty o –format possiamo specificare come deve essere formattato l’output. (medium è il valore di default che mostra un modesto numero di informazioni come nell’esempio riportato in alto) Per un elenco dettagliato dei valori permessi, è possibile consultare la documentazione. (git help log) Oltre al valore di default, l’opzione –pretty=oneline o semplicemente –oneline è una delle alternative più utili specie se usata in combinazione con altre opzioni. In quest’ultimo caso vengono infatti elencati i commit su una sola linea come mostrato nell’esempio che segue.

# comando equivalente a git log --pretty=oneline
[ test_git_repo ] (master) $ git log --oneline
5629806 Aggiunge il file_0.txt e aggiorna file_1.txt
c604875 first commit

Possiamo visualizzare maggiori dettagli in merito ai branch, tag e HEAD usando l’opzione –decorate.

[ test_git_repo ] (master) $ git log --oneline --decorate
5629806 (HEAD -> master, tag: tag_semplice, tag: annotated_tag) Aggiunge il file_0.txt e aggiorna file_1.txt
c604875 first commit

Altre due opzioni utili sono –stat e -p (oppure -u o –patch). La prima permette di mostrare quali file sono stati modificati per ogni commit con le informazioni relative a quante righe del file sono state aggiunte o rimosse. La seconda mostra la differenza (la patch) di ciascun file fra la versione del commit attuale e quella del commit precedente. Nell’esempio che segue combiniamo l’uso di queste due opzioni con –oneline al fine di rendere l’output del comando più leggibile.

[ test_git_repo ] (master) $ git log --oneline --stat
5629806 Aggiunge il file_0.txt e aggiorna file_1.txt
 file_0.txt | 1 +
 file_1.txt | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)
c604875 first commit
 file_1.txt        | 1 +
 folder/file_1.txt | 1 +
 folder/file_2.txt | 1 +
 3 files changed, 3 insertions(+)

# -p è equivalente a --patch
[ test_git_repo ] (master) $ git log --oneline -p
5629806 Aggiunge il file_0.txt e aggiorna file_1.txt
diff --git a/file_0.txt b/file_0.txt
new file mode 100644
index 0000000..da3b618
--- /dev/null
+++ b/file_0.txt
@@ -0,0 +1 @@
+file_0
diff --git a/file_1.txt b/file_1.txt
index 887ae93..b02de46 100644
--- a/file_1.txt
+++ b/file_1.txt
@@ -1 +1 @@
-ciao
+file_1
c604875 first commit
diff --git a/file_1.txt b/file_1.txt
new file mode 100644
index 0000000..887ae93
--- /dev/null
+++ b/file_1.txt
@@ -0,0 +1 @@
+ciao
diff --git a/folder/file_1.txt b/folder/file_1.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/folder/file_1.txt
@@ -0,0 +1 @@
+hello
diff --git a/folder/file_2.txt b/folder/file_2.txt
new file mode 100644
index 0000000..45b983b
--- /dev/null
+++ b/folder/file_2.txt
@@ -0,0 +1 @@
+hi

È anche possibile combinare le due opzioni appena viste attraverso –patch-with-stat.

[ test_git_repo ] (master) $ git log --patch-with-stat
5629806 Aggiunge il file_0.txt e aggiorna file_1.txt
 file_0.txt | 1 +
 file_1.txt | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/file_0.txt b/file_0.txt
new file mode 100644
index 0000000..da3b618
--- /dev/null
+++ b/file_0.txt
@@ -0,0 +1 @@
+file_0
diff --git a/file_1.txt b/file_1.txt
index 887ae93..b02de46 100644
--- a/file_1.txt
+++ b/file_1.txt
@@ -1 +1 @@
-ciao
+file_1
c604875 first commit
 file_1.txt        | 1 +
 folder/file_1.txt | 1 +
 folder/file_2.txt | 1 +
 3 files changed, 3 insertions(+)

diff --git a/file_1.txt b/file_1.txt
new file mode 100644
index 0000000..887ae93
--- /dev/null
+++ b/file_1.txt
@@ -0,0 +1 @@
+ciao
diff --git a/folder/file_1.txt b/folder/file_1.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/folder/file_1.txt
@@ -0,0 +1 @@
+hello
diff --git a/folder/file_2.txt b/folder/file_2.txt
new file mode 100644
index 0000000..45b983b
--- /dev/null
+++ b/folder/file_2.txt
@@ -0,0 +1 @@
+hi

Trascuriamo per un momento l’output dei comandi appena visti in quanto parleremo a breve del comando git diff. Vediamo invece come poter filtrare l’output del comando git log.

Possiamo usare l’opzione -n per limitare il numero di commit mostrati. In particolare verranno selezionati gli ultimi n commit presenti nel repository.

[ test_git_repo ] (master) $ git log -1
commit 562980633630afe3b9f55ed26e97ce466dda3953
Author: Claudio M <claudio@example.com>
Date:   Wed Dec 13 17:34:51 2017 +0000

  Aggiunge il file_0.txt e aggiorna file_1.txt

Con l’opzione –skip=<numero_intero> possiamo indicare il numero di commit da scartare prima di iniziare a elencare gli altri.

Se vogliamo visualizzare le informazioni sui commit che riguardano solo un determinato file, possiamo specificare il percorso del file come mostrato nell’esempio riportato sotto in cui abbiamo anche usato l’opzione –patch.

# usiamo -- per evitare ambiguità ed evidenziare che stiamo facendo riferimento a un percorso  
[ test_git_repo ] (master) $ git log --oneline --patch -- file_1.txt
5629806 Aggiunge il file_0.txt e aggiorna file_1.txt
diff --git a/file_1.txt b/file_1.txt
index 887ae93..b02de46 100644
--- a/file_1.txt
+++ b/file_1.txt
@@ -1 +1 @@
-ciao
+file_1
c604875 first commit
diff --git a/file_1.txt b/file_1.txt
new file mode 100644
index 0000000..887ae93
--- /dev/null
+++ b/file_1.txt
@@ -0,0 +1 @@
+ciao

Con l’opzione –author, che accetta un’espressione regolare o una stringa, è possibile filtrare i commit in base all’autore di questi ultimi. Riprendiamo l’esempio già visto nella terza lezione della guida e vediamo un esempio.

[ prova_git ] (master) $ git log --oneline --author="Claudio"
2fdffd3 Aggiunge moraine_lake e kakslauttanen_arctic_resort nel file mete_turistiche_dicembre.txt
0c0715f Aggiunge la destinazione nord_america/moraine_lake.txt
aded011 Aggiunge la destinazione europa/kakslauttanen_arctic_resort.txt
360d369 First commit

Verranno mostrati tutti i commit in cui "Claudio" è contenuto nel nome dell’autore.

Altra opzione utile è –grep che accetta anche un’espressione regolare e filtra i commit in base al contenuto del messaggio.

[ prova_git ] (master) $ git log --oneline --grep="mete_turistiche"
2fdffd3 Aggiunge moraine_lake e kakslauttanen_arctic_resort nel file mete_turistiche_dicembre.txt

Possiamo inoltre usare le opzioni –since (o –after) e –until (o –before) per visualizzare i commit compresi in un determinato arco temporale. L’esempio sottostante mostrerebbe i commit aggiunti a un repository fra il 4 Dicembre 2017 e il 10 Dicembre 2017.

$ git log --after="2017-12-4" --before="2017-12-10"

Visualizzare chi ha apportato l’ultima modifica a un file con git blame

Il comando git blame può essere usato per visualizzare chi ha modificato per ultimo una precisa linea di un file.

$ git blame file.txt
85906844 (Claudio M. 2017-12-09 14:28:17 +0100 1) A
5975d464 (Claudio M. 2017-12-09 17:08:52 +0100 2) B
4aefd145 (Claudio M. 2017-12-09 17:29:36 +0100 3) C

Nel banale esempio mostrato sopra, abbiamo inserito le prime tre lettere dell’alfabeto nel file file.txt (una per riga) eseguendo ogni volta un commit. Con il comando git blame otteniamo le informazioni su chi ha effettuato per ultimo la modifica, l’istante di tempo in cui è stata effettuata e il valore di hash identificativo del commmit in cui è stata apportata la modifica. Una volta ottenute le informazioni mostrate in alto, possiamo lanciare altri comandi per visualizzare maggiori dettagli.

Il comando git diff

Il comando git diff permette di confrontare due entità e mostrare le informazioni in merito alle modifiche presenti fra le due. Possiamo per esempio comparare due file oppure due commit. È anche possibile visualizzare che tipo di modifiche sono state introdotte in un certo file fra un commit e l’altro. Il comando git diff consente di visualizzare pure le differenze fra i file della Staging Area e della Working Directory. Vediamo alcuni dei casi tipici in cui viene usato.

schema riassuntivo git diff

Differenza fra due commit

$ git diff <id_commit1> <id_commit2> [--] [percorso_di_uno_o_più_file...]

In questa prima forma permette di confrontare due diversi commit specificando i valori di hash identificativi dei due commit stessi. Otterremo una lista dei diversi file modificati e i dettagli di ciascuna modifica. Il parametro opzionale [percorso_di_uno_o_più_file…] consente di specificare il percorso di uno o più file. (Fra parentesi [] vengono indicati argomenti opzionali) In tal caso l’output del comando diff conterrà solo delle informazioni in merito ai file passati come argomento.

Vediamo un semplice esempio per capire meglio il tutto. Creiamo un file a.txt all’interno di una nuova cartella come quello riportato sotto.

// a.txt
1
2

3
4
5

Aggiungiamo il file al repository.

$ git add .
$ git commit -m 'Aggiunge il file a.txt'

A questo punto modifichiamo il file a.txt presente nella working directory e aggiungiamo la nuova versione al repository.

// a.txt
1


3
100
5
6
$ git add .
$ git commit -m 'Aggiorna a.txt'
$ git log --oneline
c9720d9 Aggiorna a.txt
14ed600 Aggiunge il file a.txt

Eseguiamo il comando git diff fra i due commit e analizziamo l’output. Avendo aggiunto il solo file a.txt, verranno visualizzate delle informazioni solo su quest’ultimo.

$ git diff 14ed600 c9720d93

diff --git a/a.txt b/a.txt
index 134d005..97cf824 100644
--- a/a.txt
+++ b/a.txt
@@ -1,6 +1,7 @@
 1
-2
+

 3
-4
+100
 5
+6

L’output del comando git diff

Il comando appena eseguito genera una patch nel formato "unified" che andremo a descrivere brevemente soffermandoci sui punti di maggiore interesse.

diff --git a/a.txt b/a.txt

Partiamo dalla prima riga in cui viene semplicemente indicato il tipo di comando eseguito per generare la patch.

La seconda riga contiene invece dei dettagli sui file di tipo Blob, salvati internamente da Git all’interno della cartella .git/objects, per le due diverse versioni del file a.txt. Possiamo visualizzare il contenuto di tali file, ovvero visualizzare le due versioni del file a.txt, usando il comando git cat-file -p (es. git cat-file 134d005 -p, per visualizzare la versione iniziale)

Vengono quindi elencati i due file: la prima versione è identificata dal simbolo , la seconda da +++

Sulla riga successiva è riportato un intervallo di righe (@@ -1, 6 +1, 7 @@) in un particolare formato per evidenziare quali righe del file sono interessate dalle modifiche apportate.

@@ -riga_iniziale_file_originale, numero_di_righe  +riga_iniziale_file_modificato, numero_di_righe @@

Il resto dell’output del comando serve per riportare il contenuto del file originale in cui però ogni riga inizia con un carattere speciale.

I caratteri usati sono i seguenti:

  • ‘ ‘ (uno spazio), se la riga è presente in entrambi i file
  • -, se la riga è presente solo nel file originale
  • +, se la riga è presente nel file modificato ma non nell’originale

Altre forme del comando git diff

Facendo nuovamente riferimento allo schema dell’immagine in alto, possiamo dire che il comando git diff può essere invocato in diversi modi. Possiamo per esempio visualizzare la differenza fra Working Area e Staging Area digitando semplicemente git diff oppure confrontare la Staging Area con il commit corrente attraverso git diff –cached. Allo stesso modo possiamo comparare il Working Tree sempre con il commit corrente utilizzando git diff HEAD. Le possibilità sono innumerevoli. Per esempio, potremmo voler visualizzare il confronto fra due file presenti nella working directory con le rispettive versioni presenti in un certo commit. (git diff <commit> — percorso/al/file1.js percorso/file2.html) Per questo motivo il consiglio resta quello di leggere la documentazione (git help diff).

Conclusioni

In questa lezione abbiamo fatto una panoramica di alcuni dei comandi più utili per visualizzare ed ispezionare file, commit, working area, staging area e repository. Nel prossimo articolo parleremo dei Branch che sono costituiscono una delle principali funzionalita di Git.

Pubblicità