Learn Git with Bitbucket Cloud

Learn how to undo changes in Git using Bitbucket Cloud

Objective

Scopri come annullare le modifiche sul tuo computer locale e su un repository di Bitbucket Cloud mentre collabori con altre persone.

Mission Brief

Comandi trattati in questo tutorial: git revert, git reset, git log e git status

Ora Pubblico Prerequisiti

40 minuti

Questo tutorial presuppone familiarità con i seguenti comandi git:

git clone, git commit, git pull e git push
Hai installato Git
Hai un account Bitbucket

Sbagliare è umano. Non tutti i push sono perfetti, quindi questo tutorial ti spiegherà come usare le funzioni git più comuni per annullare una o più modifiche in modo sicuro.

Questo tutorial presuppone familiarità con i seguenti comandi git:

Se non conosci questi comandi, possiamo aiutarti a Imparare a usare Git con Bitbucket Cloud. Poi torna qui e scopri come annullare le modifiche. Questi comandi git possono essere applicati a un ambiente Windows o UNIX. Questo tutorial utilizzerà le utility della riga di comando UNIX per spiegare la navigazione dei file di sistema.

Undoing changes on your local machine

Se la modifica che desideri annullare si trova sul tuo sistema locale e non è stato eseguito il push a un repository remoto, esistono due modi principali per annullarla:

Comando Definizione

git revert

Un comando "undo", ma non una tradizionale operazione di annullamento. Anziché rimuovere il commit, inverte le modifiche nel commit e aggiunge poi un nuovo commit con il contenuto inverso. In questo modo la cronologia di Git non va perduta, il che è fondamentale per garantire l'integrità della cronologia delle tue revisioni e una collaborazione affidabile.

git reset

Un comando git versatile per annullare le modifiche. Il comando git reset include una vasta gamma di opzioni, ma in questo tutorial utilizzeremo solo le seguenti modalità di ripristino:

  • --soft: effettua il ripristino del valore HEAD nel commit che selezioni. Funziona sostanzialmente come git checkout , ma non crea uno stato head separato.
  • --mixed: effettua il ripristino del valore HEAD nel commit che selezioni nella cronologia e annulla le modifiche nell'indice.
  • --hard: effettua il ripristino del valore HEAD nel commit che selezioni nella cronologia e annulla le modifiche sia nell'indice che nella tua directory di lavoro. In questo tutorial non testeremo un hard reset.

Per una descrizione dettagliata del funzionamento del comando git reset, leggi Git Tools - Reset Demystified (Strumenti Git - Demistificazione del ripristino) su git-scm.com.

In questo tutorial, imparerai a usare molti altri comandi git che possono esserti utili per l'annullamento delle modifiche. Iniziamo!

Fork a repository

Creiamo innanzitutto un repository unico con tutti i codici sorgente. In questa fase stiamo eseguendo il "fork del repository": si tratta di una procedura git estesa che ha luogo quando si ospita un repository condiviso con un servizio di hosting di terzi come Bitbucket.

  1. Inserisci o clicca sul seguente URL: https://bitbucket.org/atlassian/tutorial-documentation-tests/commits/all
  2. Clicca sul simbolo + sulla barra laterale di sinistra, quindi seleziona Esegui il fork di questo repository, controlla la finestra di dialogo e clicca su Esegui il fork del repository.
  3. Verrai indirizzato alla panoramica del nuovo repository.
  4. Clicca sul simbolo + e seleziona Clona questo repository.
  5. Clona il repository sul tuo computer.
  6. Accedi alla Directory contenente il repository clonato.

Ora che hai un repository pieno di codici e una cronologia esistente sul tuo sistema locale, puoi iniziare ad annullare alcune modifiche.

Find changes on your local system

Ovviamente devi saper individuare la modifica che desideri annullare. Puoi fare questo sfogliando l'interfaccia utente di commit su Bitbucket e usando alcune utility della riga di comando che possono individuare una modifica specifica.

git status

Il comando git status consente di visualizzare lo stato corrente della tua directory di lavoro (la posizione del repository sul tuo sistema locale) e dell'area di gestione (dove prepari un insieme di modifiche da aggiungere alla cronologia del progetto) e mostrerà tutti i file a cui hai apportato modifiche e se tali modifiche sono state aggiunte all'area di gestione. Ora eseguiamo il comando git status ed esaminiamo lo stato attuale del repository.

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

Qui l'output del comando git status ci mostra che è tutto aggiornato con il branch master remoto e non sono presenti modifiche in attesa del commit. Nel prossimo esempio apporteremo alcune modifiche al repository e lo esamineremo nel caso in cui vi siano modifiche in sospeso. Ciò significa che il tuo sistema locale contiene modifiche ai file nel repository che non hai preparato (o indicizzato) per l'aggiunta alla cronologia del progetto.

Per illustrare questo esempio, apri innanzitutto il file myquote2.html. Apporta alcune modifiche ai contenuti di myquote2.html, salva ed esci dal file. Eseguiamo di nuovo il comando git status per esaminare il repository in questo stato.

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
 
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git checkout -- <file>..." to discard changes in working directory)
 
 Modified: myquote2.html
 
no changes added to commit (use "git add" and/or "git commit -a")
--

Qui l'output mostra che il repository contiene modifiche in sospeso in myquote2.html. Buone notizie! Se la modifica che desideri annullare non è stata ancora aggiunta, come nell'esempio qui sopra, all'area di gestione, puoi modificare il file e procedere. Git inizia a monitorare una modifica solo quando la aggiungi all'area di gestione ed esegui poi il commit nella cronologia del progetto.

Ora "annulliamo" le modifiche che abbiamo apportato a myquote2.html. Poiché si tratta di un esempio molto semplice con modifiche minime, abbiamo a disposizione due metodi per annullare le modifiche. Se eseguiamo git checkout myquote2.html, il repository ripristinerà myquote2.html alla versione del commit precedente. In alternativa, possiamo eseguire il comando git reset --hard, che riconvertirà l'intero repository all'ultimo commit.

git log

Il comando git log ti consente di elencare la cronologia del progetto, filtrarla e cercare modifiche specifiche. Mentre git status ti consente di esaminare la directory di lavoro e l'area di gestione, git log mostra solo la cronologia del commit.

Puoi trovare lo stesso log della cronologia del commit nell'interfaccia utente di Bitbucket accedendo ai commit di un repository. Puoi trovare i commit del nostro repository demo al seguente indirizzo: https://bitbucket.org/dans9190/tutorial-documentation-tests/commits/all. L'output sarà simile a quello dell'utility della riga di comando git log e può esserti utile per trovare e identificare un commit da annullare.

Nel prossimo esempio puoi vedere diversi elementi nella cronologia, ma di fatto ogni modifica consiste in un commit che dovremo trovare e annullare.

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working tree clean

$ git log

commit 1f08a70e28d84d5034a8076db9103f22ec2e982c
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Wed Feb 7 17:06:50 2018 +0000

    Initial Bitbucket Pipelines configuration

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700

    repeated quote to show how a change moves through the process

commit 4801b87c2147dce83f1bf31acfcffa6cb1d7e0a5
Merge: 1a6a403 3b29606
Author: Dan Stevens [Atlassian] <dstevens@atlassian.com>
Date:   Fri Jul 29 18:45:34 2016 +0000

    Merged in changes (pull request #6)

    Changes

Analizziamo più nel dettaglio uno dei commit nella lista:

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700
 
    repeated quote to show how a change moves through the process

Come puoi notare, ogni messaggio di commit contiene quattro elementi:

Elemento Descrizione

Hash del commit

Una stringa alfanumerica (codificata con SHA-1) che identifica questa modifica specifica

Autore

La persona che ha eseguito il commit della modifica

Data

La data in cui è stato eseguito il commit della modifica nel progetto

Messaggio di commit

Una stringa di testo che descrive le modifiche.

Suggerimento: scrivi messaggi di commit brevi e descrittivi e contribuirai alla creazione di un repository di lavoro migliore per tutti.


Locate a specific commit

Molto probabilmente la modifica che desideri annullare si troverà abbastanza indietro nella cronologia del progetto, che può essere molto ampia. Impariamo quindi alcune operazioni di base che consistono nell'usare il comando git log per trovare una modifica specifica.

  1. Accedi alla finestra del tuo terminale e vai al livello superiore del tuo repository locale usando il comando cd (cambia directory).
$ cd ~/repos/tutorial-documentation-tests/

Inserisci il comando git log --oneline. Aggiungendo --oneline, visualizzerai ogni commit su una riga separata e vedrai una porzione maggiore di cronologia nel tuo terminale.

Premi il tasto q per uscire dal log di commit e tornare al tuo prompt dei comandi in qualsiasi momento.

Il prossimo esempio mostra ciò che vedrai:

$ git log --oneline
1f08a70 (HEAD -> master, origin/master, origin/HEAD) Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
...
  1. Premi il tasto q per tornare al tuo prompt dei comandi.
  2. Individua il commit con l'hash c5826da e altre modifiche nella lista che ha prodotto il comando git log. Qualcuno non ha scritto un messaggio di commit descrittivo, quindi dovremo capire se sono presenti le modifiche di cui abbiamo bisogno.
  3. Evidenzia e copia l'hash di commit c5826da dal risultato di git log nella finestra del terminale.
  4. Digita git show, quindi incolla o trascrivi l'hash del commit che hai copiato e premi Invio. Dovresti vedere quanto segue:
$git show c5826daeb6ee3fd89e63ce35fc9f3594fe243605
commit c5826daeb6ee3fd89e63ce35fc9f3594fe243605
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Tue Sep 8 13:50:23 2015 -0700

    more changes

diff --git a/README.md b/README.md
index bdaee88..6bb2629 100644
--- a/README.md
+++ b/README.md
@@ -11,12 +11,7 @@ This README would normally document whatever steps are necessary to get your app
 ### How do I get set up? ###

 * Summary of set up
-* Configuration
-* Dependencies
-* Database configuration
-* How to run tests
-* Deployment instructions
-* more stuff and things
:

La compilazione del prompt in basso proseguirà fino a quando non mostrerà la modifica completa. Premi q per uscire dal tuo prompt dei comandi.

Filter the git log to find a specific commit

Puoi filtrare e modificare l'output del comando git log con le seguenti integrazioni:

Questo filtro Fa questo Questo comando di esempio Ha come risultato
-

Limita il numero di commit mostrati

git log -10

I 10 commit più recenti nella cronologia

--after

--before

Limita i commit mostrati all'intervallo di tempo correlato

Puoi anche usare --after "aaaa-mm-gg" --before "aaaa-mm-gg"

git log --after 2017-07-04

Tutti i commit dopo il 4 luglio 2017

--author="nome"

Elenca tutti i commit il cui autore corrisponde al nome

git log --author="Alana"

Tutti i commit eseguiti da qualsiasi autore con Alana nel campo del nome

--grep="stringa del messaggio"

Riporta tutti i commit con un messaggio di commit che corrisponde alla stringa che hai inserito

git log --grep="HOT-"

Tutti i commit che contengono la stringa di testo HOT- nel messaggio

Ti abbiamo presentato una breve panoramica del comando git log. Forse ti interesserà dare un'occhiata anche al tutorial avanzato del comando git log.

Undo a change with git reset

Per iniziare, annulliamo l'ultimo commit nella cronologia. In questo caso, supponiamo che tu abbia appena abilitato le pipelines CI/CD di Bitbucket ma hai capito che lo script non è del tutto corretto.

  1. Inserisci git log --oneline nella finestra del tuo terminale.
  2. Copia l'hash del commit per il secondo commit nel log: 52f823c, quindi premi q per uscire dal log.
  3. Inserisci git reset --soft 52f823c nella finestra del tuo terminale. Il comando dovrebbe essere eseguito in background se ha esito positivo. Ecco fatto! Hai apportato la tua prima modifica. Ora vediamo il risultato di questa azione.
  4. Inserisci git status nella finestra del tuo terminale e vedrai che il commit è stato annullato ed è diventato una modifica senza commit. Dovrebbe avere il seguente aspetto:
$ git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)
 
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
 
    new file:   bitbucket-pipelines.yml
  1. Inserisci git log --oneline nella finestra del tuo terminale. Dovresti vedere quanto segue:
$ git log --oneline
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
...
  1. Noterai che il nuovo valore HEAD del branch è il commit 52f823c, che è esattamente ciò che volevi.
  2. Premi q per uscire dal log. Lascia aperto il tuo terminale perché, ora che sai eseguire un semplice ripristino, proveremo a fare qualcosa di un po' più complesso.

Undo several changes with git reset

Supponiamo che tu abbia necessità di modificare la pull request #6 (4801b87) e mantenere una cronologia pulita. Dovrai reimpostare il valore HEAD nel commit 1a6a403 e questa volta userai il comando git reset.

  1. Inserisci git log --online
  2. Copia l'hash del commit 1a6a403 (modificato in myquote online con Bitbucket), che corrisponde al commit nella pull request #6 contenente le modifiche che desideriamo annullare.
  3. Inserisci git reset 1a6a403 nella finestra del tuo terminale. L'output dovrebbe avere il seguente aspetto:
$ git reset 1a6a403
Unstaged changes after reset:
M README.md
M myquote2.html

Noterai che ora le modifiche sono in uno stato "senza commit". Ciò significa che abbiamo rimosso diverse modifiche sia dalla cronologia del progetto che dall'area di gestione.

  1. Inserisci git status nella finestra del tuo terminale. L'output dovrebbe avere il seguente aspetto:

$ git status
On branch master
Your branch is behind 'origin/master' by 6 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)
 
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 
    modified:   README.md
    modified:   myquote2.html
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
 
    bitbucket-pipelines.yml
 
no changes added to commit (use "git add" and/or "git commit -a")

Ora puoi vedere che la prima modifica che abbiamo annullato (il file bitbucket-pipelines.yml) non è tracciata da git. Questo perché git reset rimuove la modifica sia dalla testa del branch che dall'area di monitoraggio o dell'indice di git. Il processo alla base è più complesso di quanto sembri. Puoi approfondire questo argomento in git reset.

  1. Inserisci git log --oneline nella finestra del tuo terminale.
1a6a403 myquote edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'master' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
879f965 adding to the quote file
8994332 Merged in HOT-235 (pull request #2)
b4a0b43 removed sarcastic remarks because they violate policy.
b5f5199 myquote2.html created online with Bitbucket
b851618 adding my first file
5b43509 writing and using tests

Ora l'output del log mostra che è stata modificata anche la cronologia del commit e inizia con il commit 1a6a403. A titolo esemplificativo, supponiamo ora di voler annullare il ripristino che abbiamo appena eseguito. Dopo ulteriori considerazioni, forse preferiamo mantenere i contenuti della pull request #6.

Pushing resets to Bitbucket

Il comando git reset costituisce uno dei pochi metodi "annulla" offerti da Git. In genere il ripristino viene considerato un'opzione "non sicura" per annullare le modifiche. Va bene quando si lavora localmente su un codice isolato ma diventa rischioso quando lo condivi con i membri del team.

Per condividere un branch che è stato ripristinato con un team in remoto, è necessario eseguire un "push forzato". Puoi avviare un "push forzato" eseguendo git push -f. Un push forzato distruggerà qualsiasi cronologia sul branch successiva all'ultimo push.

Segue un esempio di questo scenario "non sicuro":

  • Lo sviluppatore A sta lavorando su un branch per sviluppare una nuova funzione.
  • Lo sviluppatore B sta lavorando sullo stesso branch per sviluppare un'altra funzione.
  • Lo sviluppatore B decide di ripristinare il branch a uno stato precedente al momento in cui gli sviluppatori A e B hanno iniziato a lavorare.
  • Lo sviluppatore B esegue quindi il push forzato per ripristinare il branch al repository remoto.
  • Lo sviluppatore A esegue il pull del branch per ricevere eventuali aggiornamenti. Durante questa fase, lo sviluppatore A riceve l'aggiornamento forzato. Questo ripristina il branch locale dello sviluppatore A a una versione precedente e i commit vanno perduti.

Undo a git reset

Finora abbiamo passato gli hash SHA dei git commit ai git reset. Ora l'output di git log non contiene i commit che abbiamo ripristinato. Come possiamo recuperarli? Git non elimina mai completamente un commit a meno che non sia stato rimosso anche il puntatore. Inoltre Git memorizza un log separato di tutte le operazioni, definito "reflog". Possiamo esaminare il reflog eseguendo il comando git reflog.

1a6a403 HEAD@{0}: reset: moving to 1a6a403
1f08a70 HEAD@{1}: reset: moving to origin/master
1f08a70 HEAD@{2}: clone: from git@bitbucket.org:dans9190/tutorial-documentation-tests.git

Il tuo output di git reflog dovrebbe essere simile a quello mostrato sopra. Puoi vedere una cronologia delle azioni sul repository. La riga in alto è un riferimento all'operazione che abbiamo eseguito per ripristinare la pull request #6. Ora eseguiamo un'ulteriore operazione di ripristino della pull request #6. La seconda colonna dell'output di questo reflog indica un puntatore a un'azione di modifica eseguita sul repository. Qui HEAD@{{0}} è un riferimento al comando di ripristino che abbiamo eseguito in precedenza. Non vogliamo rispondere a quel comando di ripristino, quindi ripristineremo il repository a HEAD@{{1}}.

$ git reset --hard HEAD@{1}
HEAD is now at 1f08a70 Initial Bitbucket Pipelines configuration

Esaminiamo ora la cronologia dei commit dei repository con git log --oneline:

$git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'master' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

Qui possiamo vedere che la cronologia del commit del repository è stata ripristinata alla versione precedente con cui stavamo lavorando. Possiamo vedere che il commit 4801b87 è stato ripristinato, anche se sembrava perduto nella prima operazione di ripristino. Il comando git reflog è uno strumento molto utile per annullare le modifiche nel repository. Ulteriori informazioni nella pagina git reflog.

git revert

Gli esempi precedenti hanno illustrato alcune operazioni di annullamento usando git reset e git reflog. Git contiene un'altra utility "annulla" che viene spesso considerata "più sicura" rispetto al ripristino. L'inversione crea nuovi commit che invertono le modifiche apportate ai commit specificati. È possibile eseguire in modo sicuro il push di questi commit di inversione in repository remoti per poterli condividere con altri sviluppatori.

La seguente sezione mostrerà l'uso del comando git revert. Continuiamo con l'esempio della sezione precedente. Per iniziare, esaminiamo il log e troviamo un commit da invertire.

$ git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'master' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

Per questo esempio selezioniamo il commit 1f08a70 più recente come commit su cui operare. In questo caso, supponiamo di voler annullare le modifiche apportate nel commit. Esegui:

$ git revert 1f08a70

Avvierai un flusso di lavoro git merge. Git creerà un nuovo commit il cui contenuto consiste in un'inversione del commit specificato per l'inversione. Git aprirà quindi un editor di testo configurato per eseguire un nuovo messaggio di commit. L'inversione è considerata l'opzione di annullamento più sicura a causa di questo flusso di lavoro di commit. La creazione di commit di inversione lascia una traccia evidente nella cronologia dei commit, che testimonia il momento in cui è stata eseguita l'operazione di annullamento.

You just learned how to undo changes!

Congratulazioni, hai completato il tutorial. Torna qui in qualsiasi momento o vai alla sezione Annullamento delle modifiche per approfondire questo argomento. Continua così!