Ripristino di un vecchio commit Git in un repository pubblico


802

Come posso fare il rollback a un commit specifico in git ?

La migliore risposta che qualcuno potrebbe darmi era usare git revertX volte fino a quando non raggiungo il commit desiderato.

Quindi diciamo che voglio tornare a un commit che è vecchio di 20 commit, dovrei eseguirlo 20 volte.

C'è un modo più semplice per farlo?

Non riesco a usare reset perché questo repository è pubblico.


1
git revert <commit> non funziona?
Miku,

8
Come indicato nella mia domanda, questo non mi aiuta davvero se voglio tornare a qualcosa che 20 commette fa.
David,

7
Questa domanda è stata piuttosto bene risposto qui stackoverflow.com/questions/4114095/...~~V~~singular~~3rd
user7610

4
Non è chiaro cosa intendi per "rollback". Significa che vuoi passare temporaneamente la tua copia di lavoro a una particolare revisione? Oppure vuoi ripristinare definitivamente la cronologia del tuo repository a una certa revisione?

1
Dovresti accettare una risposta ed eventualmente votare le altre risposte che ti piacciono.
Nabil Kadimi,

Risposte:


1194

Prova questo:

git checkout [revision] .

dove si [revision]trova l'hash di commit (ad esempio:) 12345678901234567890123456789012345678ab.

Non dimenticare il .alla fine, molto importante. Ciò applicherà le modifiche all'intero albero. Dovresti eseguire questo comando nella radice del progetto git. Se ci si trova in una qualsiasi sottodirectory, questo comando modifica solo i file nella directory corrente. Quindi impegnati e dovresti essere bravo.

Puoi annullare questo

git reset --hard 

che eliminerà tutte le modifiche dalla directory di lavoro e dall'area di gestione temporanea.


7
@AlexReisner Quel periodo alla fine si trova nella directory in cui ci si trova attualmente, che non è necessariamente l'intero progetto git, giusto? Se volessi applicare le modifiche all'intero progetto, useresti invece ': /' come in 'git add: /', se non fossi attualmente nella radice del progetto git?
MSpreij,

10
nota: se da allora hai aggiunto nuovi file al tuo progetto, questo non li cancellerà. Quindi, quando vai a compilare (a seconda della tua piattaforma), potresti avere ancora errori. Elimina i nuovi file e sei a posto.
TheWestIsThe ...

6
@MSpreij Dovresti eseguire questo comando nella radice del progetto git. Se ci si trova in una qualsiasi sottodirectory, questo comando modifica solo i file nella directory corrente.
volatilevar

3
È fantastico quando puoi clonare un progetto in un'altra directory e usare git checkout [revisione]. per tornare a una revisione specifica e quindi confrontarlo con lo stesso progetto in un'altra directory. Risparmia molto tempo.
Donato,

4
Dannazione, ho dimenticato il "." che danno ho fatto al mio repository?
Gufo

196

Per eseguire il rollback a un commit specifico:

git reset --hard commit_sha

Per eseguire il rollback di 10 commit indietro:

git reset --hard HEAD~10

Puoi usare "git revert" come nel seguente post se non vuoi riscrivere la cronologia

Come ripristinare il repository Git a un commit precedente?


4
unica differenza tra questo approccio e "git checkout [revisione]". è che quest'ultimo conserva le revisioni.
Deeshank,

53
Questa risposta è ERRATA in quanto OP afferma specificamente "Non posso usare il reset perché questo repository è pubblico"
Yarin,

4
Se il repository è pubblico, penso che non ci sia modo di eseguire il rollback del commit sul repository pubblico senza usare force push (git push -f) in quanto influenzerà le persone che hanno inserito le modifiche prima del rollback. Pertanto, il ripristino può essere utilizzato anche nella sandbox locale di un repository pubblico.
Naga Kiran,

4
È fantastico che questo eviti una TESTA staccata! Proprio quello che stavo cercando.
cyber-monaco,

1
Nel mio caso ha funzionato, quindi usa 'git pull' per avanzare rapidamente indietro dopo aver testato le regressioni, ecc.
Peter Quiring,

86

Bene, immagino che la domanda sia: cosa intendi con "rollback"? Se non puoi resetperché è pubblico e vuoi mantenere intatta la cronologia del commit, vuoi dire che vuoi solo che la tua copia di lavoro rifletta un commit specifico? Utilizzare git checkoute l'hash di commit.

Modifica: come è stato sottolineato nei commenti, l'utilizzo git checkoutsenza specificare un ramo ti lascerà in uno stato "nessun ramo". Utilizzare git checkout <commit> -b <branchname>per effettuare il checkout in un ramo o git checkout <commit> .per effettuare il checkout nel ramo corrente.


Questo non ti mette nello stato strano 'Attualmente non su alcun ramo'? Come si impegnano le modifiche per completare il rollback?
Alex Reisner,

Bene, sto solo suggerendo l'uso di git checkout- è libero di controllare in qualsiasi ramo (attuale o nuovo) che desidera. Aggiornerò la mia risposta in modo che non sia ambigua.
Ben

2
Ho provato questo, ma non credo che questo sia il modo corretto di farlo perché lascia i file stagnanti. Questo non elimina i file che non erano nell'ultimo commit.
David,

3
Se ti trovi in ​​una directory di lavoro e rimani nel master, devi git reseteliminare quei file, che dici di non voler fare. Prova a farlo in un ramo separato:, git checkout <commit> -b <branchname>non avrai file stagnanti in quel ramo .
Ben

2
Il problema con l'utilizzo checkoutè che non eliminerà i file aggiunti in un commit precedente.

42

Il poster originale afferma:

La migliore risposta che qualcuno potrebbe darmi era usare git revertX volte fino a quando non raggiungo il commit desiderato.

Quindi diciamo che voglio tornare a un commit che è vecchio di 20 commit, dovrei eseguirlo 20 volte.

C'è un modo più semplice per farlo?

Non riesco a utilizzare il ripristino perché questo repository è pubblico.

Non è necessario utilizzare git revertX volte. git revertpuò accettare un intervallo di commit come argomento, quindi è necessario utilizzarlo solo una volta per ripristinare un intervallo di commit. Ad esempio, se si desidera ripristinare gli ultimi 20 commit:

git revert --no-edit HEAD~20..

L'intervallo di commit HEAD~20..è breve HEAD~20..HEADe significa "inizia dal 20 ° genitore del commit HEAD e ripristina tutti i commit successivi fino a HEAD".

Ciò ripristinerà gli ultimi 20 commit, supponendo che nessuno di questi sia commit di merge. Se ci sono commit di unione, non puoi ripristinarli tutti in un solo comando, dovrai ripristinarli singolarmente con

git revert -m 1 <merge-commit>

Nota anche che ho provato ad usare un intervallo git revertusando git versione 1.9.0. Se stai usando una versione precedente di git, usare un intervallo con git revertpuò o non può funzionare.

In questo caso, git revertè preferito sopra git checkout.

Nota che a differenza di questa risposta che dice di usaregit checkout , git revert in realtà rimuoverai tutti i file che sono stati aggiunti in qualsiasi commit che stai ripristinando , il che rende questo il modo corretto di ripristinare una serie di revisioni.

Documentazione


Nota : questo crea un nuovo commit con le modifiche ripristinate. Perfetto per la domanda di OP. Ma assicurati che sia quello che vuoi. (Gli esempi nel documento git-revert collegato sopra sono eccellenti.) Se invece desideri indagare su commit precedenti (cioè prima di scegliere a quale commit ripristinare) usa l'opzione di checkout menzionata in altre risposte, tenendo presente i commenti che altri hanno fatto su file cancellati.
SherylHohman,

@SherylHohman Il ripristino di un commit precedente non crea un nuovo commit. Non riesco a immaginare cosa intendi qui.

27

Passaggio 1: recuperare l'elenco di commit:

git log

Otterrai un elenco come in questo esempio:

[Comp:Folder User$ git log
commit 54b11d42e12dc6e9f070a8b5095a4492216d5320
Author: author <author@gmail.com>
Date:   Fri Jul 8 23:42:22 2016 +0300

This is last commit message

commit fd6cb176297acca4dbc69d15d6b7f78a2463482f
Author: author <author@gmail.com>
Date:   Fri Jun 24 20:20:24 2016 +0300

This is previous commit message

commit ab0de062136da650ffc27cfb57febac8efb84b8d
Author: author <author@gmail.com>
Date:   Thu Jun 23 00:41:55 2016 +0300

This is previous previous commit message
...

Passaggio 2: copia l'hash di commit necessario e incollalo per il checkout:

git checkout fd6cb176297acca4dbc69d15d6b7f78a2463482f

È tutto.


11
git read-tree -um @ $commit_to_revert_to

lo farà. È "git checkout" ma senza aggiornare HEAD.

Puoi ottenere lo stesso effetto con

git checkout $commit_to_revert_to
git reset --soft @{1}

se preferisci mettere insieme i comandi di convenienza.

Questi ti lasciano con il tuo albero di lavoro e l'indice nello stato desiderato, puoi solo git commitper finire.


Questo è l'unico approccio diretto che ha funzionato come un incantesimo! Ho controllato da capo, ho eseguito questo comando e ha rimosso con successo i file aggiunti che avevamo introdotto e ripristinato tutte le modifiche. Eccellente.
kamranicus,

6

Vuoi la modalità staccata HEAD?

Se desideri eseguire il rollback del tempo X per un determinato commit con una DETACHED HEAD (il che significa che non puoi sbagliare nulla), allora usa sicuramente quanto segue:

(sostituisci X con il numero di commit che desideri ripristinare)

git checkout HEAD~X

IE per tornare indietro di un commit:

git checkout HEAD~1

1
Rimuoverei la parte con ... difficile da credere ... Sembra personale, e anche qualcuno l'ha menzionata in un commento sopra, e anche in @ken nella sua risposta.
meJustAndrew

@meJustAndrew Lo è, così tante risposte su SO che confondono le persone, è abbastanza fastidioso.
Karl Morrison,

Che risposta semplice e diretta.
Ammad,

2

Diciamo che lavori su un progetto e dopo circa un giorno. Noti che una funzione ti sta ancora dando errori. Ma non sai quale modifica hai apportato che ha causato l'errore. Quindi devi pescare impegni di lavoro precedenti. Per ripristinare un commit specifico:

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 .

Ok, quindi l'impegno funziona per te. Niente più errori. Hai individuato il problema. Ora puoi tornare all'ultimo commit:

git checkout 792d9294f652d753514dc2033a04d742decb82a5 .

E controlla un file specifico prima che causasse l'errore (nel mio caso uso l'esempio Gemfile.lock):

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 -- /projects/myproject/Gemfile.lock

E questo è un modo per gestire gli errori che hai creato in commit senza rendersene conto in seguito.


2

Puoi trovare l'id di commit relativo a ciascun commit nella sezione commit di GitHub / BitBucket / Gitlab. È molto semplice, supponiamo che il tuo ID di commit sia 5889575, quindi se vuoi tornare a questa parte nel tuo codice, devi semplicemente digitare

git checkout 5889575 .

Questo ti porterà a quel momento nel tuo codice.


1

Non sono sicuro di cosa sia cambiato, ma non sono in grado di effettuare il checkout di un commit specifico senza l'opzione --detach. Il comando completo che ha funzionato per me è stato: git checkout --detach [commit hash]

Per tornare dallo stato distaccato ho dovuto controllare la mia filiale locale: git checkout master


Il check-out masterrisolve il problema di rimanere distaccato, mentre faceva git reset --hardo git checkout -- .ha funzionato ma è rimasto distaccato
DarkCygnus

0

Ecco un esempio per farlo

    cd /yourprojects/project-acme 


    git checkout efc11170c78 .
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.