Git è uno strumento potente per il controllo delle versioni e vanta una sorta di monopolio in questo settore. Per la maggior parte delle attività quotidiane, Git è semplice da usare grazie alla ripetizione dei comandi. Tuttavia, ci sono situazioni in cui c’è bisogno di qualcosa di più delle basi. A questo proposito, esistono molti comandi Git avanzati che possono portare le vostre abilità nell’utilizzo di Git a un livello superiore.

Questo step vi introdurrà anche a vari concetti di Git che di solito non si incontrano affatto. Ad esempio, l’archiviazione invece del commit delle modifiche, il rebasing e l’aggiunta di file all’area di staging. Una volta appresi questi concetti, vi ritroverete a essere ancora più indispensabili per il vostro team.

In questo articolo, presentiamo diversi comandi, ma per utilizzarli dovrete avere ben salde alcune competenze, concetti e informazioni. Cominciamo da questo.

Prerequisiti Consigliati

Sebbene non sia troppo complicato apprendere le basi di Git e utilizzare alcuni comandi intermedi, come ad esempio git delete, per gestire i comandi avanzati avremo bisogno di altri strumenti.

I suggerimenti che condividiamo qui non sono adatti a chi è alle prime armi con Git, quindi se il controllo versioni in generale è un argomento nuovo per voi, consigliamo di dedicare un po’ di tempo utilizzando regolarmente i comandi di base prima di cercare di aggiungerne altri al vostro repertorio.

In breve, ecco un rapido elenco degli aspetti che sarà necessario conoscere bene:

  • Concetti fondamentali di Git come commit, branch, pull request e altro.
  • Familiarità con i comandi Git di base come git add, git merge, git commit e git push.
  • Per le attività Git avanzate, dovrete essere in grado di navigare in un terminale.

È utile avere esperienza di lavoro con Git come parte di un team, perché molti di questi comandi possono avere un impatto significativo su una codebase condivisa. Ad esempio, potreste utilizzare alcuni di questi comandi solo in una posizione di responsabilità. Ciò significa che dovrete fare attenzione e capire quando utilizzare questi comandi.

Git Avanzato: 12 Potenti Comandi da Conoscere

Il resto di questo articolo tratterà 12 diversi comandi Git avanzati che vi porteranno oltre le basi e vi trasformeranno in dei maghi di Git. Cominciamo con un comando che potreste usare più di altri.

1. Rebasing

Innanzitutto, il rebasing è un potente comando Git che rappresenta un’alternativa a una richiesta di pull. Permette di inserire tutti i nuovi commit effettuati dopo una divergenza di branch in un nuovo branch e di inserire le modifiche all’estremità della base. Questo vi sarà utile se volete incorporare le modifiche da un altro branch senza creare un commit di fusione per qualsiasi motivo.

Un caso d’uso comune del rebasing è quando si sta lavorando su un branch di funzionalità e si vogliono incorporare le modifiche dal branch principale senza creare un commit merge. Questo aiuta a mantenere pulita la cronologia del progetto, anche se può richiedere più tempo per l’esecuzione e potreste vedere più errori durante il merging.

Per eseguire il rebase di un branch, usate il comando git rebase. Ecco un esempio in cui stiamo effettuando il rebase di un branch su un altro:

git checkout foo-branch

git rebase main

Potete anche elencare i commit che state per rilasciare e darvi la possibilità di modificarli in anticipo. In questo modo, potrete “schiacciare” i commit, modificare i messaggi di commit e altro ancora. Potete usare il flag --interactive o --i per eseguire un “rebase interattivo”.

git rebase --interactive <other-branch-name>

A questo proposito, schiacciare i commit in un unico commit per riordinare la cronologia dei commit è un caso d’uso comune del rebase. Questo può rendere la cronologia dei commit più facile da leggere e da capire.

Per farlo durante un rebase, seguite il flag con il numero di commit che volete schiacciare, che unirà i commit in uno solo:

git rebase -i HEAD~3

In questo modo si aprirà una finestra interattiva di rebase, simile a quella dei commit, in cui potrete scegliere e modificare i commit che volete eliminare:

Una finestra parziale del terminale che mostra l'output di un comando git rebase. La schermata mostra tre commit, insieme agli ID hash e al comando 'pick'. Sotto, c'è un elenco di comandi che aiutano a creare un rebase personalizzato.
Esecuzione di un rebase git nel terminale.

Nella parte superiore dello schermo è presente un elenco di commit e nella parte inferiore una selezione di comandi, oltre ad altre informazioni rilevanti. L’opzione predefinita è pick, che seleziona un commit come quello da utilizzare senza alcuna modifica.

Tuttavia, ci sono molti altri comandi che vi aiutano a gestire un rebase. Ad esempio, potete riformulare un commit o schiacciare più commit insieme. Per apportare modifiche e utilizzare i comandi, dovrete lavorare con l’editor del vostro terminale. Spesso l’editor predefinito è Vim, quindi dovrete conoscerlo bene.

Il passo finale è quello di salvare le modifiche e di inviarle al branch remoto.

2. Reversing, reset e unstaging

Git è famoso quando si tratta di annullare le modifiche. In generale, si tratta di un processo difficile che tende a restituire errori. Tuttavia, se si apportano delle modifiche alla directory di lavoro o all’area di staging che volete annullare, ci sono alcuni comandi Git che possono aiutarvi.

Infatti, Git vi dà indicazioni su come annullare un file se eseguite un comando git status:

Una finestra del terminale che mostra l'utente che esegue un comando git status. L'output mostra il ramo corrente e le modifiche da apportare. Ci sono anche le istruzioni per disinstallare un file.
Git mostra come annullare un file durante il suo output di stato.

In questo modo potete rimuovere un commit dal branch corrente e inviarlo altrove con facilità:

git reset HEAD <commit>

Questo ha l’effetto di spostare il branch indietro di un commit, come se si rimuovesse l’ultimo commit conosciuto. Potreste anche avere un caso d’uso in cui desiderate ripristinare un branch al suo stato originale. In questo caso, potete ripristinare il branch rispetto all’origine remota, ad esempio utilizzando git reset --hard origin/main. Tuttavia, tenete presente che queste modifiche saranno perse per sempre.

Sebbene il comando git checkout sia uno di quelli che utilizzerete spesso e sia considerato di base, potete anche usarlo per eliminare i file prima di un commit:

git checkout -- <filename>

Notate lo spazio tra i trattini e il segnaposto del nome del file. In questo caso, il comando cancella il file specificato e scarta le modifiche dalla directory di lavoro. Questo comando cancellerà tutte le modifiche locali apportate a un file. Per questo motivo, controllate due o tre volte che non vi servano le modifiche non salvate.

Potete anche utilizzare git revert per le modifiche apportate a un commit. Tuttavia, questo non annulla le modifiche ma crea un nuovo commit basato sull’annullamento delle modifiche all’interno del commit precedente.

La differenza principale è che il comando non sposta alcun puntatore di riferimento al nuovo commit ma mantiene i vecchi commit. Questo è utile quando si vogliono annullare le modifiche senza rimuoverle dalla cronologia dei commit.

Il comando si aspetta di ricevere un riferimento ed è semplice ripristinare l’ultimo commit:

git revert HEAD

Tuttavia, esistono molte altre possibilità di ripristinare e modificare file e commit. Le prossime due voci di questo elenco di comandi avanzati di Git le esamineranno.

3. Ripristinare i file allo stato predefinito

Con Git è possibile ripristinare facilmente un file allo stato predefinito utilizzando un comando abbastanza nuovo: git restore. In effetti, dovreste considerare questo comando come un sostituto di git reset nella maggior parte delle circostanze, in quanto offre molte più potenzialità. Ad esempio, potete ottenere lo stesso risultato con git restore --staged <filename> e con git reset HEAD.

Il comando può fare di più: è anche in grado di ripristinare i file agli stati predefiniti. Potete vedere come eseguendo anche git status :

git restore <filename>

Questo rimuoverà le modifiche dalla directory di lavoro come se nulla fosse accaduto. Come nel caso di git checkout -- <filename>, dovete assicurarvi di non volere nessuna delle modifiche locali, perché saranno perse per sempre.

4. Modificare i commit

È probabile che capiti spesso di inviare un commit e di accorgersi di aver dimenticato di includere qualcosa di importante. Con Git, si può facilmente modificare il commit per includere le modifiche mancanti.

Per farlo, è necessario seguire un processo specifico:

  • Per prima cosa, apportate le modifiche ai file che vi servono per il progetto.
  • Aggiungetele in staging come di consueto usando git add.
  • Ricomponete le modifiche nell’area di staging utilizzando un altro comando per effettuare il commit:
git commit --amend

In questo modo si modifica il commit originale con quello nuovo utilizzando l’area di staging. Per questo motivo, assicuratevi di non aver bisogno della vecchia versione del commit, perché andrà persa. Vi consigliamo inoltre di utilizzare il flag --amend con i commit locali piuttosto che con quelli remoti, per motivi simili a quelli che abbiamo illustrato altrove in questo post.

Potete anche utilizzare git commit --amend per modificare solo il messaggio di commit con il seguente comando:

git commit --amend -m "New commit message"

5. Usare i log di Git

L’uso del log di Git è prezioso per aiutarvi a capire la storia di un repository. Tuttavia, non definiremmo il comando git log come avanzato. Al contrario, potete utilizzare diverse opzioni per filtrare l’output in base alle vostre esigenze:

git log

git log --decorate

git log --stat

Ad esempio, decorando una voce del log vengono stampati i nomi di riferimento di tutti i commit mostrati. L’opzione --stat mostra gli inserimenti e le eliminazioni di un commit:

Una finestra del terminale che mostra l'output di un comando git log --stat. Mostra due commit, con l'hash evidenziato in oro, l'autore, la data del commit, il messaggio di commit e il numero di file modificati e inseriti.
Esecuzione di un comando git log –stat nel terminale.

Potete anche utilizzare altre opzioni per personalizzare l’output del log – chiamato “limitazione dei commit”. Ad esempio, prendete i seguenti comandi:

git log --author=<author-name>

git log --grep=<pattern-string>

In questo caso, potete filtrare il log in base a nomi di autori specifici o a modelli di testo. In realtà, è possibile combinare più opzioni e flag per generare un log per uno scopo specifico. Ad esempio, prendete questo comando:

git log --oneline --author=<author-name> --since=<date> feature-temp

Questo comando cerca tutti i commit con il branch feature-temp di un singolo autore a partire da una data specificata, quindi li stampa utilizzando voci a riga singola. Notate che il parametro <date> può anche essere una stringa:

--since=”Two weeks ago”

Inoltre, se volete cercare un file specifico invece di un branch, potete eseguire:

git log --oneline --author=bartonfink --since=”5 days ago” -- readme.rm

Questa serie di esempi sfiora solo la superficie di ciò che si può fare con i log, ma c’è molto spazio per trovare i commit esatti all’interno di essi in base ai vostri criteri di ricerca.

6. Hook Git

Probabilmente a volte utilizzate macro e altri script automatizzati per aiutare l’esecuzione del codice. Anche Git include questo tipo di funzionalità sotto forma di hook. Questi script vengono eseguiti automaticamente in risposta a determinati eventi, come i commit o i push. Esistono anche molti modi per utilizzare gli hook per imporre la formattazione del codice, eseguire test e molto altro ancora.

Esistono due tipi di hook: lato client e lato server:

  • Gli hook lato client si attivano in base ad azioni locali come i commit e le fusioni.
  • Gli hook lato server si attivano in seguito a operazioni di rete. Ad esempio, quando un repo riceve un commit in push, e molti altri esempi.

Git popolerà sempre il repo con diversi hook di esempio una volta eseguito un git init. Tuttavia, per poterli utilizzare, dovrete rimuovere l’estensione .sample:

Una finestra del Finder in macOS che mostra la cartella hooks nascosta di un repo Git. Contiene una serie di file di script di hook di esempio, ciascuno con estensione .sample.
Una cartella in macOS che mostra gli hook di esempio che Git installa all’avvio.

Notate che è possibile eseguire solo un tipo di hook alla volta, anche se si possono utilizzare più script contemporaneamente con un po’ di lavoro. Per questo motivo, i nomi dei file devono corrispondere al tipo di hook che desiderate utilizzare in base agli script di esempio: pre-commit, update e così via.

Creare un hook Git

Per creare un hook Git, dovete creare uno script eseguibile nella sottodirectory .git/hooks senza estensione. Verrà comunque eseguito se lo aggiungerete alla cartella hooks.

Potete utilizzare il linguaggio di scripting che preferite, purché possa essere eseguito come un file eseguibile. Noi suggeriamo Ruby o Python, ma potete usare anche Bash, Perl e molti altri. Tutto ciò che dovete fare è cambiare il percorso del vostro interprete rispetto a quello predefinito di Bash:

#!/usr/bin/env python

Da qui potrete scrivere il vostro codice come di consueto. Ad esempio, ecco uno script prepare-commit in Python che chiede all’utente di scrivere dei messaggi di commit:

#!/usr/bin/env python

import sys, os

path_commit_msg = sys.argv[1]

with open(commit_msg_filepath, 'w') as f:

f.write("# You’ll need to provide a better commit message than that, buddy!")

Anche se non è sempre necessario, vi consigliamo di eseguire chmod +x .git/hooks/<hook-name> dalla linea di comando per assicurarvi di poterlo eseguire.

Nel complesso, gli hook possono essere uno strumento potente per automatizzare le attività ripetitive e imporre le best practice all’interno del vostro team.

7. Riferimenti ai commit

In Git, i commit sono identificati dall’hash di crittografia SHA-1. Anche se è possibile fare riferimento ai commit con il loro hash completo, quest’operazione può essere noiosa e soggetta a errori:

bc7623b7a94ed3d8feaffaf7580df3eca4f5f5ca

Invece, Git offre diversi modi per fare riferimento ai commit usando nomi più brevi e memorabili. Ad esempio, è possibile usare il nome di un branch o di un tag. Consideriamo un branch chiamato “develop”. Ecco un esempio in cui ci riferiamo all’ultimo commit di questo branch:

git diff develop..HEAD

Questo mostra le differenze tra l’ultimo commit (HEAD) sul branch “develop” e il commit attuale.

Potete anche fare riferimento a un commit in base alla sua posizione relativa nella cronologia dei commit. Ad esempio, potete fare riferimento a due commit precedenti a quello attuale utilizzando la stenografia HEAD~2:

git diff HEAD~2..HEAD

Git offre anche altri modi per riferirsi ai commit, come ad esempio il simbolo “@” per riferirsi al branch corrente o il simbolo “^” per riferirsi al genitore di un commit. Utilizzando queste notazioni abbreviate, potrete risparmiare tempo ed evitare errori mentre lavorate con i commit.

8. Stashing

In circostanze normali, si potrebbe pensare che non esista un modo per memorizzare le modifiche apportate ai file senza effettuare il commit. Lo “stashing” è un modo per farlo in maniera temporaneo. È utile quando avete bisogno di cambiare branch o di lavorare su un’attività diversa ma non volete ancora eseguire il commit delle modifiche.

Ad esempio, se avete bisogno di cambiare branch per lavorare su qualcosa a metà del flusso, potete mettere le modifiche nel branch corrente e fare il checkout dell’altro. Da lì, potete lavorare sull’altro branch, quindi eseguire il commit e il push delle modifiche. Potrete poi fare il checkout e recuperare il lavoro sul branch originale.

Per conservare le modifiche ci sono due modi:

git stash

Questo salva le modifiche in un nuovo stash e riporta la directory di lavoro all’ultimo commit HEAD (lo stato in cui si trovava prima di apportare le nuove modifiche). Potete elencare le modifiche usando git stash list e ispezionare lo stash usando git stash show. Quest’ultimo comando può anche accettare qualsiasi formato accettato da git diff.

Da qui è possibile cambiare branch o lavorare su un’altra attività. Quando volete recuperare le modifiche, eseguite il comando:

git stash apply

In questo modo verranno applicate le ultime modifiche alla cartella di lavoro. Tuttavia, tenete presente che se modificate troppo il file, potete ancora incorrere in conflitti. Dopotutto, git stash è una soluzione temporanea al problema in questione.

È anche possibile avere più stash e specificare quale stash applicare utilizzando la seguente procedura:

git stash apply stash@{n}

Il segnaposto {n} contiene un numero intero e stash@{0} rappresenta l’ultimo stash. La documentazione ufficiale di Git include altri esempi di git stash.

9. Bisecting

Scommettiamo che a tutti sarà capitato di imbattersi in un bug o in un problema e di non avere idea di dove iniziare a cercare. In queste situazioni, il “bisecting” può aiutare a identificare rapidamente il commit che ha introdotto il problema.

In poche parole, il comando va a caccia di bug attraverso una ricerca dei commit. Una volta trovato il commit incriminato, ve lo restituisce. Il potere di questo comando è dato da tutti i sottocomandi che potete utilizzare.

Per usare bisecting, dovete prima eseguire il comando git bisect start. Git vi porterà al primo commit nella cronologia del progetto.

Da qui, dovrete indicare se quel commit è buono o cattivo utilizzando i comandi corrispondenti:

git bisect good

git bisect bad

Git vi porterà quindi al commit successivo per verificarne la “qualità”. È anche possibile sostituire “good” con “old” e “bad” con “new” per adattarlo al vostro caso d’uso specifico (ma non si possono mischiare i termini)

Da qui, si può continuare a contrassegnare ogni commit come buono o cattivo finché non trovate il commit che ha introdotto il bug. Tuttavia, non è necessario spulciare ogni commit: potete specificare degli identificatori esatti per restringere e abbreviare la ricerca:

git bisect bad feature-test

In questo caso si utilizza il nome di un branch, ma potrebbe trattarsi di una revisione specifica utilizzando un numero intero, un riferimento hash e altro ancora. In ogni caso, una volta trovato il bug, potete eseguire uno dei seguenti comandi per tornare al codice più recente:

git bisect reset

Come per tutti i comandi Git avanzati di questo elenco, c’è molto altro da capire e la documentazione di Git sarà una lettura essenziale.

10. Confrontare i branch

La nostra voce sui riferimenti dei commit parla dell’utilizzo di git diff. Ora è arrivato il momento di analizzare questo aspetto in modo più dettagliato. Vi capiterà spesso di avere più branch che contengono modifiche diverse. Git vi permette di confrontare le differenze tra due branch utilizzando il comando git diff. In realtà, potete usarlo in molti modi, spesso insieme ad altri comandi, per indagare e analizzare un repo.

Il comando di base git diff vi fornirà un output con una panoramica delle modifiche. Assomiglia molto all’output di un’indagine di commit merge:

Una parte della finestra del terminale che mostra un tipico output di git diff. Mostra i file confrontati, i riferimenti all'indice, la chiave e la legenda delle modifiche tra i documenti e le modifiche stesse.
L’output di una richiesta di git diff.

Tuttavia, è possibile arrivare fino ai branch esatti, agli hashtag e molto altro ancora. Ad esempio, per confrontare due branch, eseguite il comando git diff branch1..branch2 e sostituite i placeholder:

git diff feature-branch pre-prod

Potete anche confrontare le differenze tra il branch attuale e un altro branch:

git diff HEAD..pre-prod

Notate che utilizzando due punti in questo caso si otterrà la differenza tra le due punte dei branch. Al contrario, tre punti restituiranno la differenza tra gli antenati comuni dei due branch e la utilizzeranno per il test.

Come per git log, potete ripulire l’output e perfezionare i risultati. Ad esempio, git diff --name-only branch1..branch2 verificherà solo quali file differiscono tra loro e tralascerà il contesto:

Una parte di una finestra del terminale che mostra come eseguire un comando git diff --name-only. Restituisce un elenco di soli nomi di file, come da comando.
Esecuzione di un comando git diff –name-only nel terminale.

Potreste notare che l’output è difficile da analizzare, soprattutto se il “diff” è lungo. In questi casi, potete utilizzare l’opzione --color-words:

Una finestra del terminale che mostra il lungo output di una richiesta di git diff, completo di riferimenti di colore per le parole. Mostra quali file vengono confrontati, i riferimenti espliciti alle modifiche e alle cancellazioni tra i file e le modifiche stesse dei file. Ciascuna di esse ha una codifica a colori per aiutarci a distinguerle dal resto del testo.
Esecuzione del comando git diff –color-words e visualizzazione dell’output nel terminale.

Nel complesso, git diff può essere potente quanto altri comandi, soprattutto quando richiamate alcune opzioni e perfezionate le differenze da restituire.

11. Applicare singoli commit

A volte potreste voler applicare un commit specifico da un branch a un altro senza unire i due branch. Git permette di farlo utilizzando git cherry-pick. Dovreste usarlo con attenzione, ma git cherry-pick può esservi utile in alcuni casi.

Una delle possibili situazioni è quella in cui si hanno dei branch di funzionalità obsolete di cui non effettuate il merge con main o trunk. Potete usare una combinazione di comandi (come git log) per estrarre i vecchi commit rilevanti e riapplicarli altrove.

Usate git log per trovare il riferimento di un commit. Da lì, assicuratevi di essere nel branch di cui volete prelevare un riferimento. Ad esempio, supponiamo che vogliate prelevare il commit xxxxxaaaaaa nel branch “trunk“. Per prima cosa, fate il checkout del branch.

git checkout trunk

… poi fate il cherry-pick del commit:

git cherry-pick xxxxxaaaaaa

È probabile che il messaggio di commit non sia aggiornato in molte occasioni. Per risolvere questo problema, potete passare l’opzione --edit al comando. In questo modo potrete fornire un nuovo messaggio di commit prima di effettuare il cherry pick.

12. Potenziare “git add”

Per il nostro ultimo comando avanzato di Git, vi mostreremo git add. No, non è un errore di battitura: questo comando fondamentale di Git ha una potenza sorprendente.

Ad esempio, se vi trovate ad aggiungere singoli file all’area di staging, potete usare il seguente comando:

git add -p

L’opzione -p vi permette di mettere in staging le modifiche in modo interattivo. Potete rivedere le modifiche apportate a ciascun file e poi scegliere quali aggiungere allo staging. Questo vi farà risparmiare molto tempo e vi aiuterà a evitare di mettere in staging una modifica indesiderata.

Sebbene sia possibile mettere in staging i singoli file, è bene notare che si può anche specificare una directory. Ad esempio, per mettere in staging tutti i file all’interno della directory “new-feature“:

git add new-feature

Potreste anche voler vedere quale sarà il risultato di un git add senza eseguire il processo completo. Per questo c’è un’opzione:

git add --dry-run

git add -n

Quando lo eseguite, Git vi mostrerà se aggiungerà o ignorerà i file. A proposito dei file ignorati, potete anche aggiungerli all’area di staging se lo desiderate:

git add --force

git add -f

L’aggiunta di file all’area di staging può essere più complessa di un semplice scenario binario “Aggiungi o non aggiungi”. Per questo motivo, uno dei comandi principali di Git può coprire una miriade di eventualità.

Riepilogo

Una volta imparati i comandi base di Git, avrete l’80% di ciò che serve per svolgere le normali attività di controllo della versione del vostro progetto. Tuttavia, l’ultimo 20% racchiude i casi d’uso in cui i comandi Git avanzati possono dare il meglio.

Comandi e tecniche come rebasing, bisecting, il ripristino dei file e molto altro ancora vi permetteranno di risolvere velocemente ogni problema. Inoltre, potrete offrire un valore aggiunto al vostro team e al vostro progetto e contribuire a snellire i flussi di lavoro, ad aumentare la produttività e ad avere un impatto migliore come developer.

Qualcuno di questi comandi Git avanzati entrerà a far parte del vostro lavoro quotidiano? Fatecelo sapere nella sezione commenti qui sotto!

Jeremy Holcombe Kinsta

Content & Marketing Editor presso Kinsta, web developer di WordPress e content writer. Al di fuori di tutto ciò che riguarda WordPress, mi piacciono la spiaggia, il golf e il cinema. Ho anche i problemi di tutte le persone più alte della media ;).