Reimpostazione, checkout e ripristino
I comandi git reset
, git checkout
e git revert
sono alcuni degli strumenti Git disponibili più utili. Tutti ti consentono di annullare qualche tipo di modifica nel tuo repository e i primi due comandi possono essere usati per manipolare i commit o i singoli file.
Poiché sono così simili, è molto facile confondersi su quale comando usare in un determinato scenario di sviluppo. In questo articolo, confronteremo le configurazioni più comuni di git reset
, git checkout
e git revert
. Lo scopo è darti la sicurezza necessaria per navigare nel tuo repository usando uno di questi comandi.
È utile pensare a ciascun comando in termini del suo effetto sui tre meccanismi di gestione dello stato di un repository Git: la directory di lavoro, l'istantanea in staging e la cronologia dei commit. Questi componenti sono talvolta noti come i "tre alberi" di Git. Esploriamo i tre alberi in modo approfondito nella pagina di git reset
. Tieni a mente questi meccanismi mentre leggi questo articolo.
Un checkout è un'operazione che sposta il puntatore di riferimento HEAD
su un commit specificato. Per dimostrarlo, considera il seguente esempio.

Questo esempio dimostra una sequenza di commit sul branch main
. Il riferimento HEAD
e il riferimento del branch main
puntano attualmente a commit d. Ora eseguiamo git checkout b

Si tratta di un aggiornamento dell'albero «Cronologia commit». Il comando git checkout
può essere utilizzato in un commit o in un ambito a livello di file. Un checkout a livello di file cambierà il contenuto del file con quello del commit specifico.
Un ripristino è un'operazione che richiede un commit specificato e crea un nuovo commit che lo inverte. git revert
può essere eseguito solo a livello di commit e non ha funzionalità a livello di file.
Un ripristino è un'operazione che richiede un commit specificato e reimposta i "tre alberi" in modo che corrispondano allo stato del repository in quel commit specificato. Un ripristino può essere richiamato in tre diverse modalità che corrispondono ai tre alberi.
Il checkout e il ripristino sono generalmente utilizzati per effettuare «annullamenti» locali o privati. Modificano la cronologia di un repository, il che può causare conflitti quando si esegue il push su repository condivisi remoti. Il ripristino è considerato un'operazione sicura per gli «annullamenti pubblici» in quanto crea una nuova cronologia che può essere condivisa in remoto e non sovrascrive la cronologia da cui i membri del team remoto possono dipendere.
Riferimenti Git Reset, Revert e Checkout a confronto
La tabella seguente riassume i casi d'uso più comuni per tutti questi comandi. Assicurati di tenere questo riferimento a portata di mano, poiché sicuramente dovrai usarne almeno alcuni durante la tua carriera con Git.
Comando | Ambito | Casi d'uso comuni |
---|---|---|
git reset | Livello di commit | Elimina i commit in un branch privato o eliminare le modifiche senza commit |
git reset | Livello di file | Rimuovi lo stage di un file |
Git checkout | Livello di commit | Passa da un branch all'altro o controlla le vecchie istantanee |
Git checkout | Livello di file | Ignora le modifiche nella directory di lavoro |
git revert | Livello di commit | Annulla i commit in un branch pubblico |
git revert | Livello di file | (N/D) |
Operazioni a livello di commit
I parametri che passi a git reset
e git checkout ne
determinano l'ambito. Quando non includi il percorso di un file come parametro, funzioneranno su commit interi. Questo è ciò che esploreremo in questa sezione. Nota che git revert
non ha una controparte a livello di file.
Ripristinare un commit specifico
A livello di commit, il ripristino è un modo per spostare la punta di un branch su un altro commit. Può essere usato per rimuovere i commit dal branch corrente. Ad esempio, il comando seguente sposta il branch hotfix
indietro di due commit.
git checkout hotfix git reset HEAD~2
I due commit alla fine dell'hotfix
ora sono sospesi o orfani. Ciò significa che verranno eliminati la prossima volta che Git eseguirà una raccolta dei rifiuti. In altre parole, questi commit andranno scartati. Questo può essere visualizzato come segue:

Questo utilizzo di git reset
è un modo semplice per annullare le modifiche che non sono state condivise con altri. È il comando ideale quando inizi a lavorare su una funzionalità e ti ritrovi a pensare: «Oh cavolo, cosa sto facendo? Dovrei semplicemente ricominciare da capo.»
Oltre a spostare il branch corrente, puoi anche far sì che git reset
modifichi l'istantanea in staging e/o la directory di lavoro passando uno dei seguenti flag:
--soft
: l'istantanea in staging e la directory di lavoro non vengono alterate in alcun modo.--mixed
: l'istantanea in staging viene aggiornata in modo da corrispondere al commit specificato, ma la directory di lavoro non è interessata. Questa è l'opzione predefinita.--hard
: l'istantanea in staging e la directory di lavoro sono entrambe aggiornate per corrispondere al commit specificato.
È più facile pensare a queste modalità come a un modo per definire l'ambito di un'operazione git reset
. Per ulteriori informazioni dettagliate, visita la pagina di git resett
.
Eseguire il checkout dei vecchi commit
Il comando git checkout viene utilizzato per aggiornare lo stato del repository a un punto specifico della cronologia dei progetti. Quando viene passato con il nome di un branch, ti consente di passare da un branch all'altro.
git checkout hotfix
Internamente, tutto ciò che fa il comando precedente è spostare HEAD
in un altro branch e aggiornare la directory di lavoro in modo che corrisponda. Poiché ciò può sovrascrivere le modifiche locali, Git ti obbliga a salvare o inserire in stash qualsiasi modifica nella directory di lavoro che andrà persa durante l'operazione di checkout. A differenza di git reset
, git checkout
non sposta alcun branch.

Puoi anche eseguire il checkout di commit arbitrari passando il riferimento al commit anziché a un branch. L'operazione è identica al checkout di un branch e sposta il riferimento HEAD
nel commit specificato. Ad esempio, il seguente comando effettuerà il checkout del componente principale del commit corrente:
git checkout HEAD~2
Ciò è utile per ispezionare rapidamente una vecchia versione del tuo progetto. Tuttavia, poiché non esiste alcun riferimento branch all'HEAD
attuale, entrerai in uno stato di HEAD
distaccato. La cosa può rivelarsi pericolosa se inizi ad aggiungere nuovi commit perché non ci sarà modo di ripristinarli dopo il passaggio a un altro branch. Per questo motivo, dovresti sempre creare un nuovo branch prima di aggiungere commit a un HEAD
distaccato.
Annullare i commit pubblici con Revert
Il comando Revert annulla un commit creandone uno nuovo. Questo è un modo sicuro per annullare le modifiche, in quanto non ha alcuna possibilità di riscrivere la cronologia dei commit. Ad esempio, il comando seguente calcolerà le modifiche contenute nel penultimo commit, creerà un nuovo commit annullando tali modifiche e aggiungerà il nuovo commit al progetto esistente.
git checkout hotfix git revert HEAD~2
Questo può essere visualizzato come segue:
Confrontalo con git reset
, che altera la cronologia dei commit esistente. Per questo motivo, git revert
dovrebbe essere usato per annullare le modifiche su un branch pubblico e git reset
dovrebbe essere riservato all'annullamento delle modifiche su un branch privato.
Puoi anche pensare a git revert
come a uno strumento per annullare le modifiche con commit, mentre git reset HEAD
serve per annullare le modifiche senza commit.
Come git checkout
, git revert
ha il potenziale per sovrascrivere i file nella directory di lavoro, quindi ti chiederà di eseguire il commit o inserire nello stash le modifiche che andrebbero perse durante l'operazione di ripristino.
Operazioni a livello di file
I comandi git reset
e git checkout
accettano anche un percorso di file opzionale come parametro, che altera drasticamente il loro comportamento. Invece di operare su intere istantanee, questo li obbliga a limitare le operazioni a un singolo file.
Git: reimpostare un file specifico
Quando viene richiamato con un percorso di file, git reset
aggiorna l'istantanea in staging in modo che corrisponda alla versione del commit specificato. Ad esempio, questo comando recupererà la versione di foo.py
nel penultimo commit e la preparerà per il commit successivo:
git reset HEAD~2 foo.py
Come con la versione di git reset
a livello di commit, questa è più comunemente usata con HEAD
piuttosto che con un commit arbitrario. L'esecuzione di git reset HEAD foo.py
eliminerà lo staging di foo.py
. Le modifiche che contiene saranno ancora presenti nella directory di lavoro.
I flag --soft
, --mixed
e --hard
non hanno alcun effetto sulla versione a livello di file di git reset
, poiché l'istantanea in staging è sempre aggiornata e la directory di lavoro non viene mai aggiornata.
Git: eseguire il checkout di un file
Il checkout di un file è simile all'utilizzo di git reset
con un percorso del file, tranne per il fatto che viene aggiornata la directory di lavoro anziché lo staging. A differenza della versione a livello di commit di questo comando, non viene spostato il riferimento HEAD
, il che significa che non cambierai branch.
Ad esempio, il comando seguente fa sì che foo.py
nella directory di lavoro corrisponda a quello dal penultimo commit:
git checkout HEAD~2 foo.py
Proprio come l'invocazione a livello di commit di git checkout
, può essere usata per ispezionare le vecchie versioni di un progetto, ma l'ambito è limitato al file specificato.
Se esegui lo staging ed esegui il commit del file con checkout, "ripristinerai" il file alla versione precedente. Verranno anche rimosse tutte le modifiche successive al file, mentre il comando git revert
annulla solo le modifiche introdotte dal commit specificato.
Come git reset
, è comunemente usato con HEAD
come riferimento per il commit. Ad esempio, git checkout HEAD foo.py
ha l'effetto di eliminare le modifiche senza staging a foo.py
. È un comportamento simile a git reset HEAD --hard
, ma funziona solo sul file specificato.
Riepilogo
Ora dovresti avere tutti gli strumenti di cui potresti aver bisogno per annullare le modifiche in un repository Git. I comandi git reset
, git checkout
e git revert
possono creare confusione, ma se pensi ai loro effetti sulla directory di lavoro, sulle istantanee in staging e sulla cronologia dei commit, dovrebbe essere più facile capire quale comando si adatta al task di sviluppo in questione.