Resetting, checking out & reverting
The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.
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.
It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this article.
Un checkout è un'operazione che sposta il puntatore di riferimento HEAD
su un commit specificato. Per dimostrarlo, considera il seguente esempio.
materiale correlato
Come spostare un repository Git completo
Scopri la soluzione
Impara a utilizzare Git con Bitbucket Cloud
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.
Git reset vs revert vs checkout reference
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 |
---|---|---|
| Ambito Livello di commit | Casi d'uso comuni Discard commits in a private branch or throw away uncommitted changes |
| Ambito Livello di file | Casi d'uso comuni Rimuovi lo stage di un file |
| Ambito Livello di commit | Casi d'uso comuni Passa da un branch all'altro o controlla le vecchie istantanee |
| Ambito Livello di file | Casi d'uso comuni Ignora le modifiche nella directory di lavoro |
| Ambito Livello di commit | Casi d'uso comuni Annulla i commit in un branch pubblico |
| Ambito Livello di file | Casi d'uso comuni (N/D) |
Commit level operations
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.
Reset a specific commit
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.
It’s easier to think of these modes as defining the scope of a git reset
operation. For further detailed information visit the git reset page.
Eseguire il checkout dei vecchi commit
The git checkout
command is used to update the state of the repository to a specific point in the projects history. When passed with a branch name, it lets you switch between branches.
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.
Undo public commits with 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.
File-level operations
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 reset a specific file
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 checkout 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
You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.
Condividi l'articolo
Argomento successivo
Letture consigliate
Aggiungi ai preferiti queste risorse per ricevere informazioni sui tipi di team DevOps e aggiornamenti continui su DevOps in Atlassian.