Git Reset vs Revert vs Rebase

Pubblicato: 2021-05-20

In questo articolo imparerai diversi modi per giocare con i commit in Git.

Come sviluppatore, ti troveresti in queste situazioni più volte in cui avresti voluto tornare a uno dei tuoi commit precedenti ma non sei sicuro di come farlo. E anche se conosci i comandi Git come reset, revert, rebase, non sei a conoscenza delle differenze tra loro. Quindi iniziamo e capiamo cosa sono git reset, revert e rebase.

Git Reset

Git reset è un comando complesso e viene utilizzato per annullare le modifiche.

Puoi pensare a git reset come una funzione di rollback. Con git reset, puoi saltare tra vari commit. Esistono tre modalità per eseguire un comando git reset: –soft, –mixed e –hard. Per impostazione predefinita, il comando git reset utilizza la modalità mista. In un flusso di lavoro di ripristino di git, entrano in gioco tre meccanismi di gestione interni di git: HEAD , area di staging (indice) e la directory di lavoro .

git reset - geekflare

La directory di lavoro è il luogo in cui stai attualmente lavorando, è il luogo in cui sono presenti i tuoi file. Usando un comando git status, puoi vedere quali sono tutti i file/cartelle presenti nella directory di lavoro.

Staging Area (Indice) è dove git tiene traccia e salva tutte le modifiche nei file. Le modifiche salvate si riflettono nella directory .git. Usi git add "filename" per aggiungere il file all'area di staging. E come prima, quando esegui git status, vedrai quali file sono presenti nell'area di staging.

Il ramo corrente in Git è indicato come HEAD. Punta all'ultimo commit, avvenuto nel ramo di checkout corrente. Viene considerato come un puntatore per qualsiasi riferimento. Una volta effettuato il checkout in un altro ramo, anche l'HEAD si sposta nel nuovo ramo.

Lascia che ti spieghi come funziona git reset in modalità hard, soft e mixed. La modalità difficile viene utilizzata per passare al commit puntato, la directory di lavoro viene popolata con i file di quel commit e l'area di staging viene ripristinata. Nel ripristino software, solo il puntatore viene modificato nel commit specificato. I file di tutti i commit rimangono nella directory di lavoro e nell'area di staging prima del ripristino. In modalità mista (impostazione predefinita), il puntatore e l'area di staging vengono entrambi ripristinati.

Git Reset Hard

Lo scopo di git hard reset è spostare HEAD sul commit specificato. Rimuoverà tutti i commit con successo dopo il commit specificato. Questo comando cambierà la cronologia del commit e punterà al commit specificato.

In questo esempio, aggiungerò tre nuovi file, li committerò e quindi eseguirò un hard reset.

Come puoi vedere dal comando qui sotto, in questo momento, non c'è nulla da impegnare.

 $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean

Ora creerò 3 file e aggiungerò del contenuto.

 $ vi file1.txt $ vi file2.txt $ vi file3.txt

Aggiungi questi file al repository esistente.

 $ git add file*

Quando riesegui il comando status, rifletterà i nuovi file che ho appena creato.

 $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: file1.txt new file: file2.txt new file: file3.txt

Prima di eseguire il commit, lascia che ti mostri che attualmente ho un registro di 3 commit in Git.

 $ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Ora, mi impegnerò nel repository.

 $ git commit -m 'added 3 files' [master d69950b] added 3 files 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txt

Se eseguo ls-files, vedrai che i nuovi file sono stati aggiunti.

 $ git ls-files demo dummyfile newfile file1.txt file2.txt file3.txt

Quando eseguo il comando log in git, ho 4 commit e HEAD punta all'ultimo commit.

 $ git log --oneline d69950b (HEAD -> master) added 3 files 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Se vado ed elimino manualmente il file1.txt e faccio uno stato git, mostrerà il messaggio che le modifiche non sono messe in scena per il commit.

 $ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: file1.txt no changes added to commit (use "git add" and/or "git commit -a")

Ora, eseguirò il comando di ripristino completo.

 $ git reset --hard HEAD is now at d69950b added 3 files

Se ricontrollo lo stato, scoprirò che non c'è nulla da confermare e il file che ho eliminato è tornato nel repository. Il rollback è avvenuto perché dopo aver eliminato il file, non ho eseguito il commit, quindi dopo un hard reset, è tornato allo stato precedente.

 $ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean

Se controllo il registro di git, ecco come apparirà.

 $ git log commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 19:53:31 2020 +0530 added 3 files commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Lo scopo dell'hard reset è puntare al commit specificato e aggiornare la directory di lavoro e l'area di staging. Lascia che ti mostri un altro esempio. Attualmente, la visualizzazione dei miei commit è la seguente:

dacci dentro

Qui, eseguirò il comando con HEAD^, il che significa che voglio ripristinare il commit precedente (un commit back).

 $ git reset --hard HEAD^ HEAD is now at 0db602e one more commit

Puoi vedere che il puntatore della testa è ora cambiato in 0db602e da ​​d69950b.

 $ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

git duro 1

Se controlli il registro, il commit di d69950b è sparito e la testa ora punta a 0db602e SHA.

 $ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 Test

Se esegui i file ls, puoi vedere che file1.txt, file2.txt e files3.txt non sono più nel repository perché quel commit e il suo file sono stati rimossi dopo l'hard reset.

 $ git ls-files demo dummyfile newfile

Git Soft Reset

Allo stesso modo, ora ti mostrerò un esempio di soft reset. Considera, ho aggiunto di nuovo i 3 file come menzionato sopra e li ho impegnati. Il registro git apparirà come mostrato di seguito. Puoi vedere che il "soft reset" è il mio ultimo commit e anche HEAD sta indicando questo.

 $ git log --oneline aa40085 (HEAD -> master) soft reset 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

I dettagli del commit nel registro possono essere visualizzati utilizzando il comando seguente.

 $ git log commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 21:01:36 2020 +0530 soft reset commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Ora usando il soft reset, voglio passare a uno dei commit più vecchi con SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14

Per fare ciò, eseguirò il comando seguente. Devi passare più di 6 caratteri iniziali di SHA, lo SHA completo non è richiesto.

 $ git reset --soft 0db602e085a4

Ora, quando eseguo il registro git, posso vedere che HEAD è stato reimpostato sul commit che ho specificato.

 $ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Ma la differenza qui è che i file del commit (aa400858aab3927e79116941c715749780a59fc9) in cui avevo aggiunto 3 file sono ancora nella mia directory di lavoro. Non sono stati cancellati. Ecco perché dovresti usare un soft reset piuttosto che un hard reset. Non c'è rischio di perdere i file in modalità soft.

 $ git ls-files demo dummyfile file1.txt file2.txt file3.txt newfile

Git Ripristina

In Git, il comando revert viene utilizzato per eseguire un'operazione di ripristino, ad esempio per ripristinare alcune modifiche. È simile al comando reset, ma l'unica differenza qui è che esegui un nuovo commit per tornare a un particolare commit. In breve, è giusto dire che il comando git revert è un commit.

Il comando Git revert non elimina alcun dato durante l'esecuzione dell'operazione di ripristino.

Diciamo che sto aggiungendo 3 file ed eseguendo un'operazione di commit git per l'esempio di ripristino.

 $ git commit -m 'add 3 files again' [master 812335d] add 3 files again 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txt

Il registro mostrerà il nuovo commit.

 $ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Ora vorrei tornare a uno dei miei commit passati, diciamo: "59c86c9 new commit". Vorrei eseguire il comando di seguito.

 $ git revert 59c86c9

Questo aprirà un file, troverai i dettagli del commit a cui stai tentando di ripristinare e puoi dare un nome al tuo nuovo commit qui, quindi salvare e chiudere il file.

 Revert "new commit" This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch master # Your branch is ahead of 'origin/master' by 4 commits. # (use "git push" to publish your local commits) # # Changes to be committed: # modified: dummyfile

Dopo aver salvato e chiuso il file, questo è l'output che otterrai.

 $ git revert 59c86c9 [master af72b7a] Revert "new commit" 1 file changed, 1 insertion(+), 1 deletion(-)

Ora per apportare le modifiche necessarie, a differenza del ripristino, il ripristino ha eseguito un altro nuovo commit. Se controlli di nuovo il registro, troverai un nuovo commit a causa dell'operazione di ripristino.

 $ git log --oneline af72b7a (HEAD -> master) Revert "new commit" 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

git ripristinare

Git log avrà tutta la cronologia dei commit. Se si desidera rimuovere i commit dalla cronologia, ripristinare non è una buona scelta, ma se si desidera mantenere le modifiche ai commit nella cronologia, ripristinare è il comando adatto invece di ripristinare.

Git Rebase

In Git, rebase è il modo di spostare o combinare i commit di un ramo su un altro ramo. Come sviluppatore, non creerei le mie funzionalità sul ramo principale in uno scenario reale. Lavorerei sul mio ramo (un "ramo di funzionalità") e quando ho alcuni commit nel mio ramo di funzionalità con la funzionalità aggiunta, vorrei spostarlo nel ramo principale.

Rebase a volte può essere un po' confuso da capire perché è molto simile a un'unione. L'obiettivo di unire e ribasare entrambi è prendere i commit dal mio feature branch e inserirli in un branch master o in qualsiasi altro branch. Considera, ho un grafico che assomiglia a questo:

git rebase

Supponi di lavorare in team con altri sviluppatori. In tal caso, puoi immaginare che questo potrebbe diventare davvero complesso dove hai un gruppo di altri sviluppatori che lavorano su diversi rami di funzionalità e hanno unito più modifiche. Diventa confuso da tracciare.

Quindi, è qui che rebase aiuterà. Questa volta, invece di fare un merge git, farò un rebase, dove voglio prendere i miei due commit di feature branch e spostarli nel branch master. Un rebase prenderà tutti i miei commit dal feature branch e li sposterà sopra i commit del branch master. Quindi, dietro le quinte, git sta duplicando i commit di feature branch sul branch master.

git rebase 1

Questo approccio ti darà un grafico lineare pulito con tutti i commit di fila.

git ripristinare 2

Rende facile tracciare dove sono andati i commit. Puoi immaginare che se sei in un team con molti sviluppatori, tutti i commit sono ancora in fila. Quindi, è davvero facile da seguire anche se hai molte persone che lavorano allo stesso progetto contemporaneamente.

Lascia che te lo mostri praticamente.

Ecco come appare attualmente il mio ramo principale. Ha 4 commit.

 $ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Eseguirò il comando seguente per creare e passare a un nuovo ramo chiamato funzionalità e questo ramo verrà creato dal secondo commit, ovvero 59c86c9

 (master) $ git checkout -b feature 59c86c9 Switched to a new branch 'feature'

Se controlli il log nel ramo delle funzionalità, ha solo 2 commit provenienti dal master (mainline).

 (feature) $ git log --oneline 59c86c9 (HEAD -> feature) new commit e2f44fc (origin/master, origin/HEAD) test

Creerò la funzionalità 1 e la inserirò nel ramo della funzionalità.

 (feature) $ vi feature1.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 1' [feature c639e1b] feature 1 1 file changed, 1 insertion(+) create mode 100644 feature1.txt

Creerò un'altra funzionalità, ovvero la funzionalità 2, nel ramo delle funzionalità e la committerò.

 (feature) $ vi feature2.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 2' [feature 0f4db49] feature 2 1 file changed, 1 insertion(+) create mode 100644 feature2.txt

Ora, se controlli il registro del ramo delle funzionalità, ha due nuovi commit, che ho eseguito sopra.

 (feature) $ git log --oneline 0f4db49 (HEAD -> feature) feature 2 c639e1b feature 1 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Ora voglio aggiungere queste due nuove funzionalità al ramo principale. Per questo, userò il comando rebase. Dal ramo delle funzionalità, eseguirò il rebase rispetto al ramo principale. Ciò che farà è riconnettere il mio ramo di funzionalità alle ultime modifiche.

 (feature) $ git rebase master Successfully rebased and updated refs/heads/feature.

Ora vado avanti e controllo il ramo principale.

 (feature) $ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits)

E infine, ribase il ramo principale contro il mio ramo di funzionalità. Ciò richiederà quei due nuovi commit sul mio branch di funzionalità e li riprodurrà sul mio branch principale.

 (master) $ git rebase feature Successfully rebased and updated refs/heads/master.

Ora, se controllo il registro sul ramo principale, posso vedere che i due commit del mio ramo delle funzionalità sono stati aggiunti con successo al mio ramo principale.

 (master) $ git log --oneline 766c996 (HEAD -> master, feature) feature 2 c036a11 feature 1 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Si trattava di ripristinare, ripristinare e ripristinare i comandi in Git.

Conclusione

Si trattava di ripristinare, ripristinare e ripristinare i comandi in Git. Spero che questa guida passo passo sia stata utile. Ora sai come giocare con i tuoi commit secondo la necessità usando i comandi menzionati nell'articolo.