Close

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.

I tre alberi di Git

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.

Sposta il puntatore HEAD ref su un commit specificato
Database
materiale correlato

Come spostare un repository Git completo

Logo di Bitbucket
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

Sequence of commits on the main branch

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

git reset

Ambito

Livello di commit

Casi d'uso comuni

Discard commits in a private branch or throw away uncommitted changes

git reset

Ambito

Livello di file

Casi d'uso comuni

Rimuovi lo stage di un file

Git checkout

Ambito

Livello di commit

Casi d'uso comuni

Passa da un branch all'altro o controlla le vecchie istantanee

Git checkout

Ambito

Livello di file

Casi d'uso comuni

Ignora le modifiche nella directory di lavoro

git revert

Ambito

Livello di commit

Casi d'uso comuni

Annulla i commit in un branch pubblico

git revert

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:

Reimpostazione del branch hotfix su HEAD-2

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.

Moving HEAD from main to hotfix

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
Spostamento di "HEAD" verso un commit arbitrario

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:

Ripristino del penultimo commit

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.

Spostamento di un file dalla cronologia dei commit all'istantanea in staging

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.

Spostamento di un file dalla cronologia dei commit alla directory di lavoro

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.

Le persone collaborano utilizzando una parete piena di strumenti

Blog di Bitbucket

Illustrazione su Devops

Percorso di apprendimento DevOps

Funzione Demo Den per demo con esperti Atlassian

Come Bitbucket Cloud funziona con Atlassian Open DevOps

Iscriviti alla nostra newsletter DevOps

Thank you for signing up