Come posso ripristinare un repository Git a un commit precedente?


7630

Come posso tornare dal mio stato attuale a un'istantanea creata con un determinato commit?

Se lo faccio git log, ottengo il seguente output:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <me@me.com>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <me@me.com>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <me@me.com>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <me@me.com>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

Come posso ripristinare il commit dal 3 novembre, ovvero commit 0d1d7fc?



116
Ecco un post molto chiaro e completo sull'annullamento di cose in Git, direttamente da Github.
Nobita,

3
Correlati: rollback a un vecchio commit Git in un repository pubblico . Si noti che questa domanda aggiunge un vincolo al fatto che il repository sia pubblico.

58
Adoro Git, ma il fatto che ci siano 35 risposte a qualcosa che dovrebbe essere incredibilmente semplice espone un grosso problema con Git. O è la documentazione?
The Muffin Man

2
In che modo la lingua "trap" nell'usare la parola per ripristinare colloquialmente significa non resettare nemmeno qui? 6594 voti finora e non una modifica in questo modo, per sottolineare la differenza? Non sarebbe più confuso fare riferimento al "salvataggio di un file" qui con l'espressione "commit" ...
RomainValeri

Risposte:


9732

Questo dipende molto da cosa intendi per "ripristina".

Passa temporaneamente a un commit diverso

Se vuoi tornare temporaneamente ad esso, scherzare, quindi tornare dove sei, tutto ciò che devi fare è controllare il commit desiderato:

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

O se vuoi impegnarti mentre sei lì, vai avanti e crea una nuova filiale mentre ci sei:

git checkout -b old-state 0d1d7fc32

Per tornare dove eri, controlla di nuovo il ramo in cui eri. (Se hai apportato modifiche, come sempre quando cambi ramo, dovrai gestirle nel modo appropriato. Puoi resettarle per gettarle via; potresti stash, checkout, stash pop per portarle con te; potresti impegnarti li a un ramo lì se vuoi un ramo lì.)

Hard commit commit non pubblicati

Se, d'altra parte, vuoi davvero sbarazzarti di tutto ciò che hai fatto da allora, ci sono due possibilità. Uno, se non hai pubblicato nessuno di questi commit, resetta semplicemente:

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

Se sbagli, hai già eliminato le modifiche locali, ma puoi almeno tornare a dove eri prima ripristinando di nuovo.

Annulla i commit pubblicati con nuovi commit

D'altra parte, se hai pubblicato il lavoro, probabilmente non vuoi reimpostare il ramo, dal momento che è effettivamente riscrivere la cronologia. In tal caso, potresti effettivamente ripristinare gli commit. Con Git, revert ha un significato molto specifico: creare un commit con la patch inversa per annullarlo. In questo modo non riscrivi alcuna cronologia.

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

La git-revertmanpage in realtà copre molto di questo nella sua descrizione. Un altro collegamento utile è questa sezione di git-scm.com che parla di git-revert .

Se decidi di non voler ripristinare dopo tutto, puoi ripristinare il ripristino (come descritto qui) o ripristinare prima del ripristino (vedere la sezione precedente).

In questo caso potresti trovare utile questa risposta:
Come riportare HEAD in una posizione precedente? (Testa staccata)


118
Il commento di Rod su git revert HEAD~3come il miglior wat per ripristinare i 3commit è una convenzione importante.
Nuova Alessandria,

19
Potresti scrivere il numero intero? come:git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Spoeken il

16
@MathiasMadsenStav Sì, puoi ovviamente specificare i commit dall'intera SHA1. Ho usato gli hash abbreviati per rendere più leggibile la risposta, e anche tu tendi a usarli se stai scrivendo. Se stai copiando e incollando, usa sicuramente l'hash completo. Vedi Specifica delle revisioni in man git rev-parse per una descrizione completa di come si possono nominare i commit.
Cascabel,

59
È possibile utilizzare git revert --no-commit hash1 hash2 ...e successivamente eseguire il commit di ogni singolo ripristino in un commitgit commit -m "Message"
Mirko Akov,

6
Cosa significa "pubblicare" in questo contesto?
Howiecamp,

1852

Molte risposte complicate e pericolose qui, ma in realtà è facile:

git revert --no-commit 0766c053..HEAD
git commit

Questo ripristinerà tutto dall'HEAD all'hash di commit, il che significa che ricrea lo stato di commit nell'albero di lavoro come se ogni commit da allora fosse stato ripristinato. È quindi possibile eseguire il commit dell'albero corrente e questo creerà un nuovo commit sostanzialmente equivalente al commit a cui si è "ripristinato".

(La --no-commitbandiera consente a git di ripristinare contemporaneamente tutti i commit, altrimenti ti verrà richiesto un messaggio per ogni commit dell'intervallo, cosparso di cronologia con nuovi commit non necessari.)

Questo è un modo semplice e sicuro per ripristinare uno stato precedente . Nessuna cronologia viene distrutta, quindi può essere utilizzata per commit che sono già stati resi pubblici.


23
Se vuoi davvero avere singoli commit (invece di ripristinare tutto con un unico commit), puoi passare --no-editinvece --no-commit, in modo da non dover modificare un messaggio di commit per ogni reversione.

88
Se uno dei commit tra 0766c053..HEAD è una fusione, si verificherà un errore di pop-up (da fare senza specificare -m). Questo può aiutare coloro che incontrando: stackoverflow.com/questions/5970889/...
timhc22

7
Per vedere le differenze prima di impegnarti, usa git diff --cached.
John Erck,

21
$ git revert --no-commit 53742ae..HEADritornafatal: empty commit set passed
Alex G

10
@AlexG è perché devi inserire l'hash prima di quello in cui vuoi tornare. Nel mio caso, gli hash erano come: 81bcc9e HEAD{0}; e475924 HEAD{1}, ...(da git reflog) e volevo annullare quello che ho fatto 81bcc9e, quindi ho dovuto faregit revert e475924..HEAD
EpicPandaForce

1611

Roger Coder?

Lavorando da solo e vuoi solo che funzioni? Segui queste istruzioni di seguito, hanno lavorato in modo affidabile per me e molti altri per anni.

Lavorare con gli altri? Git è complicato. Leggi i commenti sotto questa risposta prima di fare qualcosa di avventato.

Ripristino della copia di lavoro in commit più recente

Per ripristinare un commit precedente, ignorando qualsiasi modifica:

git reset --hard HEAD

dove HEAD è l'ultimo commit nel tuo ramo attuale

Ripristino della copia di lavoro su un commit precedente

Per ripristinare un commit più vecchio del commit più recente:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

I crediti vanno a una domanda Stack Overflow simile, Ripristinare un commit da un hash SHA in Git? .


33
L'ho fatto, ma poi non sono stato in grado di eseguire il commit e il push nel repository remoto. Voglio che uno specifico vecchio impegno diventi HEAD ...
Lennon,

7
Significa che hai già inserito i commit che vuoi ripristinare. Può creare molti problemi per le persone che hanno verificato il tuo codice e ci stanno lavorando. Dal momento che non possono applicare il commit senza problemi al proprio. In tal caso è meglio ripristinare un git. Se sei l'unico a utilizzare il repository. Fai una git push -f (ma pensaci due volte prima di farlo)
vinothkr il

6
Ho appena Inoltre voglio sottolineare che, in alternativa, per la soluzione soft reset, invece di fare un reset misto primo e un hard reset scorso, si può effettivamente fare il reset hardware prima, come segue: git reset --hard 56e05fc; git reset --soft HEAD@{1}; git commit.

5
@nuton linus pauling stesso, il creatore di git, lo ha criticato per essere troppo complicato. Sta registrando che dice che era "scioccato" e che la popolarità è diventata così popolare data la sua complessità
boulder_ruby,

5
@boulder_ruby Penso che volevi dire che Linus Torvalds era il creatore di Git. Ma penso che Linus Pauling sarebbe probabilmente d'accordo sul fatto che git sia complicato.
Suncat2000,

215

L'opzione migliore per me e probabilmente per altri è l'opzione di ripristino Git:

git reset --hard <commidId> && git clean -f

Questa è stata l'opzione migliore per me! È semplice, veloce ed efficace!


** Nota: ** Come menzionato nei commenti, non farlo se condividi la tua filiale con altre persone che hanno copie dei vecchi commit

Anche dai commenti, se volevi un metodo meno "sfacciato", potresti usare

git clean -i

37
Avviso obbligatorio: non farlo se condividi il tuo ramo con altre persone che hanno copie dei vecchi commit, perché l'uso di un hard reset come questo li costringerà a risincronizzare il loro lavoro con il nuovo ramo di reset. Per una soluzione che spiega in dettaglio come ripristinare in modo sicuro i commit senza perdere il lavoro con un hard reset, vedere questa risposta .

7
Secondo l'avvertimento di @ Cupcake ... essere molto consapevole delle conseguenze. Nota, tuttavia, che se il tuo bisogno è davvero quello di far scomparire per sempre quei commit dalla storia, questo metodo reset + clean lo farà, e avrai bisogno di forzare il push dei tuoi rami modificati su tutti i telecomandi.
ashnazg,

5
git clean -f PERICOLO PERICOLO
Tisch

2
Questo imposta il capo della mia copia locale sul commit desiderato. Ma poi non posso inviare alcuna modifica perché è dietro il telecomando. E se estraggo dal telecomando finisce nuovamente dove era l'ultimo commit sul ramo remoto. Come posso cancellare completamente (da ogni parte) diversi commit sia sulla mia copia locale che sono stati inviati?
Ade,

2
@Ade .. Potresti usare la git push -fbandiera .. Ma fai attenzione, sovrascriverà il telecomando .. Assicurati di sapere cosa vuoi fare ...
Pogrindis,

176

Prima di rispondere, aggiungiamo alcuni retroscena, spiegando di cosa si HEADtratta.

First of all what is HEAD?

HEADè semplicemente un riferimento al commit corrente (più recente) sul ramo corrente. Può essercene solo uno HEADin qualsiasi momento (escluso git worktree).

Il contenuto di HEADè archiviato all'interno .git/HEADe contiene i 40 byte SHA-1 del commit corrente.


detached HEAD

Se non si esegue l'ultimo commit, ovvero HEADviene chiamato un commit precedente nella cronologia detached HEAD.

Inserisci qui la descrizione dell'immagine

Sulla riga di comando sarà simile al seguente: SHA-1 invece del nome del ramo poiché HEADnon punta alla punta del ramo corrente:

Inserisci qui la descrizione dell'immagine


Alcune opzioni su come recuperare da una HEAD staccata:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Questo verificherà il nuovo ramo che punta al commit desiderato. Questo comando eseguirà il checkout per un determinato commit.

A questo punto puoi creare un ramo e iniziare a lavorare da questo punto in poi:

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Puoi sempre usare refloganche quello. git reflogvisualizzerà qualsiasi modifica che ha aggiornato il HEADe il checkout della voce di reflog desiderata HEADriporterà questo commit.

Ogni volta che HEAD viene modificato, ci sarà una nuova voce in reflog

git reflog
git checkout HEAD@{...}

Questo ti riporterà al commit desiderato

Inserisci qui la descrizione dell'immagine


git reset HEAD --hard <commit_id>

"Sposta" la testa indietro sul commit desiderato.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Nota: ( da Git 2.7 ) puoi anche usare git rebase --no-autostashanche questo.

Questo schema illustra quale comando fa cosa. Come puoi vedere, reset && checkoutmodifica il HEAD.

Inserisci qui la descrizione dell'immagine


6
Eccellente suggerimento git reflog, è esattamente quello di cui avevo bisogno
smac89,

4
Ahia! Tutto questo sembra terribilmente complicato ... non c'è un semplice comando che ti fa solo un passo indietro nel processo? Come passare dalla versione 1.1 del tuo progetto alla versione 1.0? Mi aspetterei qualcosa del genere: git stepback_one_commit o qualcosa del genere ...
Kokodoko,

c'è: git reset HEAD^--hard`
CodeWizard

3
@Kokodoko Sì, è orribilmente complicato ... e un perfetto esempio di quanto poca considerazione gli esperti abbiano per le persone che hanno appena iniziato. Si prega di fare riferimento alla mia risposta qui, e anche al libro che raccomando in esso. Git NON è qualcosa che puoi semplicemente prendere in modo intuitivo. E posso essere assolutamente certo che CodeWizard non l'abbia fatto.
mike rodent,

145

Se si desidera "annullare il commit", cancellare l'ultimo messaggio di commit e rimettere in scena i file modificati, utilizzare il comando:

git reset --soft HEAD~1
  • --softindica che i file di cui non è stato eseguito il commit devono essere conservati come file di lavoro rispetto ai --hardquali li eliminerebbero.
  • HEAD~1è l'ultimo commit. Se si desidera eseguire il rollback di 3 commit, è possibile utilizzarlo HEAD~3. Se si desidera eseguire il rollback a un numero di revisione specifico, è possibile farlo utilizzando l'hash SHA.

Questo è un comando estremamente utile in situazioni in cui hai commesso la cosa sbagliata e vuoi annullare l'ultimo commit.

Fonte: http://nakkaya.com/2009/09/24/git-delete-last-commit/


3
Questo è morbido e delicato: senza rischi se non hai spinto il tuo lavoro
nilsM

124

Puoi farlo con i seguenti due comandi:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

Rimuoverà il tuo precedente commit Git.

Se desideri mantenere le modifiche, puoi anche utilizzare:

git reset --soft [previous Commit SHA id here]

Quindi salverà le tue modifiche.


2
Ho provato 1/2 dozzina di risposte in questo post fino a quando non sono arrivato a questo ... tutti quegli altri, la mia configurazione git continuava a darmi un errore quando provavo a spingere. Questa risposta ha funzionato. Grazie!
Gene Bo,

Un dettaglio per me è che ho perso i diff .. che volevo tenere per vedere cosa avevo fatto nel commit che non funzionava. Quindi la prossima volta salverei quei dati prima di emettere questo comando di reset
Gene Bo

1
Questo è stato l'unico modo per me di annullare una cattiva unione, il ripristino non ha funzionato in quel caso. Grazie!
Dave Cole,

Migliore risposta. Grazie
Imran Pollob il

La migliore risposta, grazie.
user1394

114

Ho provato molti modi per ripristinare le modifiche locali in Git e sembra che funzioni meglio se si desidera ripristinare l'ultimo stato di commit.

git add . && git checkout master -f

Breve descrizione:

  • NON creerà alcun commit come git revertfa.
  • NON staccherà la TESTA come git checkout <commithashcode>fa.
  • Sostituirà tutte le modifiche locali e ELIMINA tutti i file aggiunti dall'ultimo commit nel ramo.
  • Funziona solo con i nomi dei rami, quindi puoi ripristinare solo l'ultimo commit nel ramo in questo modo.

Ho trovato un modo molto più comodo e semplice per ottenere i risultati sopra:

git add . && git reset --hard HEAD

dove HEAD punta all'ultimo commit nella tua filiale attuale.

È lo stesso codice di codice suggerito da boulder_ruby, ma ho aggiunto git add .prima git reset --hard HEADdi cancellare tutti i nuovi file creati dall'ultimo commit poiché questo è ciò che la maggior parte delle persone si aspetta che io ritenga quando ritornano all'ultimo commit.


83

OK, tornare a un precedente commit in Git è abbastanza facile ...

Ripristina senza mantenere le modifiche:

git reset --hard <commit>

Ripristina mantenendo le modifiche:

git reset --soft <commit>

Spiegazione: utilizzando git reset, è possibile ripristinare uno stato specifico. È comune usarlo con un hash di commit come vedi sopra.

Ma come vedi la differenza sta usando le due bandiere --softe --hard, di default git resetusando la --softbandiera, ma è una buona pratica usare sempre la bandiera, spiego ogni bandiera:


--soft

Il flag predefinito come spiegato, non è necessario fornirlo, non modifica l'albero di lavoro, ma aggiunge tutti i file modificati pronti per il commit, quindi si torna allo stato di commit che le modifiche ai file non vengono messe in scena.


--difficile

Fai attenzione con questa bandiera. Ripristina l'albero di lavoro e tutte le modifiche ai file tracciati e tutto sparirà!


Ho anche creato l'immagine qui sotto che potrebbe accadere nella vita reale lavorando con Git:

Git ripristinato a un commit



70

Supponendo che stai parlando di master e su quel rispettivo ramo (detto questo, questo potrebbe essere qualsiasi ramo funzionante di cui ti occupi):

# Reset local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Reset remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

Ho trovato la risposta in un post sul blog (ora non esiste più)

Nota che si tratta di ripristinare e forzare la modifica sul telecomando, quindi se altri membri del tuo team hanno già eseguito il pull, causerai problemi per loro. Stai distruggendo la storia del cambiamento, che è un motivo importante per cui le persone usano git in primo luogo.

Meglio usare il ripristino (vedi altre risposte) che il ripristino. Se sei una squadra individuale, probabilmente non importa.


6
In che modo questa risposta è diversa dalla miriade di altre?
Matsmath,

È un peccato. Ho mandato un'email al blogger - speriamo che ce l'abbia ancora!
Markreyes,


2
La sintassi push non è presente nella maggior parte degli altri suggerimenti su come risolvere questo problema. Ha funzionato alla grande.
jpa57,

61

Supponi di avere i seguenti commit in un file di testo chiamato ~/commits-to-revert.txt(li usavo git log --pretty=onelineper ottenerli)

fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca

Crea uno script della shell Bash per ripristinare ciascuno di essi:

#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
    git revert $i --no-commit
done

Ciò ripristina tutto allo stato precedente, comprese le creazioni di file e directory, e le eliminazioni, il commit nel tuo ramo e conservi la cronologia, ma hai ripristinato la stessa struttura di file. Perché Git non ha un git revert --to <hash>è oltre me.


41
Potresti fare un git revert HEAD~3per rimuovere gli ultimi 3 commit
Rod

25
@Rod - No, non è esatto. Tale comando ripristinerà il commit che è il terzo nonno di HEAD (non gli ultimi tre commit).
kflorence,

1
@kflorence Ok grazie per le informazioni. Funzionerebbe git revert -n master~3..master~1? (Visto da kernel.org/pub/software/scm/git/docs/git-revert.html )
Rod

3
@Rod - Sembra giusto, sicuramente è una brutta sintassi, vero? Ho sempre trovato il check out del commit che voglio "ripristinare" e il commit più intuitivo.
kflorence,

7
C'è un modo molto più semplice per farlo ora che con uno script come questo, basta usare git revert --no-commit <start>..<end>, perché git revertaccetta un intervallo di commit nelle nuove (o tutte?) Versioni di Git. Si noti che l'inizio dell'intervallo non è incluso nel ripristino.

58

Alternative extra alle soluzioni Jefromi

Le soluzioni di Jefromi sono sicuramente le migliori e dovresti sicuramente usarle. Tuttavia, per completezza, volevo anche mostrare queste altre soluzioni alternative che possono anche essere utilizzate per ripristinare un commit (nel senso che si crea un nuovo commit che annulla le modifiche nel commit precedente , proprio come git revertsuccede).

Per essere chiari, queste alternative non sono il modo migliore per ripristinare i commit , lo sono le soluzioni di Jefromi , ma voglio solo sottolineare che puoi anche usare questi altri metodi per ottenere lo stesso risultato git revert.

Alternativa 1: ripristini hardware e software

Questa è una versione leggermente modificata della soluzione di Charles Bailey per ripristinare un commit da un hash SHA in Git? :

# Reset the index to the desired commit
git reset --hard <commit>

# Move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}

# Commit the changes
git commit -m "Revert to <commit>"

Questo funziona fondamentalmente utilizzando il fatto che i ripristini software lasceranno lo stato del commit precedente messo in scena nell'area dell'indice / dell'area di gestione temporanea, che sarà quindi possibile eseguire il commit.

Alternativa 2: elimina l'albero corrente e sostituiscilo con quello nuovo

Questa soluzione deriva dalla soluzione di svick per il checkout del vecchio commit e per renderlo un nuovo commit :

git rm -r .
git checkout <commit> .
git commit

Analogamente all'alternativa n. 1, questo riproduce lo stato di <commit>nella copia di lavoro corrente. È necessario git rmprima fare perché git checkoutnon rimuoverà i file che sono stati aggiunti da allora <commit>.


Sull'alternativa 1, una domanda veloce: così facendo non ci perdiamo tra i commit, giusto?
Bogac,

2
@Bogac - i punti indicano un percorso di file, in questo caso la directory corrente, quindi si presume che lo si stia eseguendo dalla radice della copia di lavoro.
Tom,

L'avvertimento viene ripetuto più volte nella risposta, ma qualcuno potrebbe aggiungere perché questi non sono il modo migliore - rispetto a qualcosa come git revert HEAD~2..HEADdalla soluzione collegata di @ Cascabel (@ Jefromi). Non vedo il problema.
Joshua Goldberg,

55

Ecco un modo molto più semplice per tornare a un precedente commit (e farlo in uno stato senza commit, a che fare con esso qualunque cosa tu voglia):

git reset HEAD~1

Quindi, non c'è bisogno di commit ID e così via :)


non ha funzionato, un git pull dopo questo produce: errore: le tue modifiche locali ai seguenti file verrebbero sovrascritte da merge:
malhal

1
@malhal Questo perché hai avuto modifiche non impegnate. Riponili / ripristinali e poi funzionerà senza quell'errore.
Paul Walczewski,

39

C'è un comando (non parte del core Git, ma è nel pacchetto git-extra ) specificamente per ripristinare e mettere in scena vecchi commit:

git back

Per la pagina man , può anche essere usato come tale:

# Remove the latest three commits
git back 3

38

Il modo migliore è:

git reset --hard <commidId> && git push --force

Ciò reimposterà il ramo al commit specifico e quindi caricherà il server remoto con gli stessi commit che hai in locale (questo eliminerà completamente i comandi dopo quel commit specifico)

Fare attenzione con il --forceflag rimuove tutti i commit successivi dopo il commit selezionato senza l'opzione per recuperarli.


3
ha funzionato come un incanto!
Gaurav Gupta,

Ho effettuato il downgrade perché non riesco a vedere come la tua risposta fornisca nuove informazioni non già fornite, ad esempio stackoverflow.com/a/37145089/1723886 , stackoverflow.com/a/27438379/1723886 o stackoverflow.com/a/48756719/1723886 . In effetti la maggior parte dei commit menziona già git reset --hard, e molti altri menzionano l'uso di --force o -f per spingere.
Alex Telon,

Fa il lavoro con un solo comando, chiaro e semplice. Sei libero di sottovalutare la mia risposta se non ti piace.
david.t_92,

1
Un'altra opzione da considerare per il futuro è quella di suggerire una modifica su una risposta precedente o aggiungere un commento dicendo che "questo può essere fatto anche in una riga usando &&" per esempio. In questo modo tutti possono quindi vedere la risposta migliorata in un unico posto.
Alex Telon,

36

Dopo tutte le modifiche, quando si premono tutti questi comandi, potrebbe essere necessario utilizzare:

git push -f ...

E non solo git push.


15
Avviso obbligatorio: non farlo se condividi la tua filiale con altre persone che hanno copie dei vecchi commit, perché l'uso di una spinta forzata come questa li costringerà a risincronizzare il loro lavoro. Per una soluzione che spiega in dettaglio come ripristinare in modo sicuro i commit senza perdere il lavoro con una spinta forzata, vedere questa risposta .

3
A volte questo è quello che vuoi. Esempio: impegnato e inviato diversi commit nel ramo sbagliato (ramo A). Dopo aver scelto la ciliegia nel ramo B, desidero che questi commit vengano rimossi dal ramo A. Non vorrei ripristinarlo, poiché il ripristino verrà successivamente applicato quando i rami A e B vengono uniti. Effettuare un reset --hard <commitId> nel ramo A seguito da una spinta forzata rimuove questi commit dal ramo preservandoli nel ramo B. Posso farcela perché so che nessun altro si sta sviluppando sul ramo A.
Doug R

Grazie! Non riuscivo a capire come far corrispondere il ramo remoto al mio ramo locale, dovevo solo fare una spinta forzata.
Mido,

32

Puoi completare tu stesso tutti questi passaggi iniziali e tornare al repository Git.

  1. Estrai l'ultima versione del tuo repository da Bitbucket usando il git pull --allcomando

  2. Esegui il comando Git log con -n 4dal tuo terminale. Il numero dopo il -ndetermina il numero di commit nel registro a partire dal commit più recente nella cronologia locale.

    $ git log -n 4
    
  3. Ripristina la testa della cronologia del tuo repository usando git reset --hard HEAD~Ndove N è il numero di commit che vuoi riprendere. Nell'esempio seguente l'head verrebbe riportato indietro di un commit, all'ultimo commit nella cronologia del repository:

  4. Invia la modifica al repository Git usando git push --forceper forzare la modifica della modifica.

Se si desidera che il repository Git esegua un commit precedente:

git pull --all
git reset --hard HEAD~1
git push --force


28

Selezionare il commit richiesto e verificarlo con

git show HEAD
git show HEAD~1
git show HEAD~2 

fino ad ottenere il commit richiesto. Per fare in modo che HEAD punti a questo, fallo

git reset --hard HEAD~1

o git reset --hard HEAD~2qualunque cosa.


7
Avviso obbligatorio: non farlo se condividi il tuo ramo con altre persone che hanno copie dei vecchi commit, perché l'uso di un hard reset come questo li costringerà a risincronizzare il loro lavoro con il nuovo ramo di reset. Per una soluzione che spiega in dettaglio come ripristinare in modo sicuro i commit senza perdere il lavoro con un hard reset, vedere questa risposta .

2
Inoltre, per essere chiari, git show HEADequivale al solo utilizzo git log HEAD -1.

25

Se la situazione è urgente e vuoi solo fare ciò che l'interrogante ha chiesto in modo rapido e sporco , supponendo che il tuo progetto si trovi in ​​una directory chiamata, ad esempio, "il mio progetto":


VELOCE E SPORCO : a seconda delle circostanze, rapido e sporco può in effetti essere molto buono. Ciò che la mia soluzione qui non c'è da non sostituire in modo irreversibile i file che avete nella vostra directory di lavorare con i file issò / estratta dalle profondità del repository git in agguato sotto la vostra .git / directory utilizzando i comandi diabolicamente intelligente e diabolicamente potente git, di cui ci sono molti. NON DEVI FARE TALE TENUTA SUBACQUEA PER RECUPERARE quella che può sembrare una situazione disastrosa, e tentare di farlo senza sufficiente esperienza può rivelarsi fatale .


  1. Copia l'intera directory e chiamala qualcos'altro, come "mio progetto - copia". Supponendo che i file del tuo repository git ("repo") siano nella directory "my project" (il posto predefinito per loro, in una directory chiamata ".git"), ora avrai copiato sia i tuoi file di lavoro che i tuoi file di repository.

  2. Fallo nella directory "il mio progetto":

    .../my project $ git reset --hard [first-4-letters&numbers-of-commit's-SHA]
    

Ciò riporterà lo stato del repository in "il mio progetto" a quello che era quando hai effettuato il commit (un "commit" significa un'istantanea dei tuoi file di lavoro). Tutti gli commit da allora andranno persi per sempre sotto "il mio progetto", MA ... saranno ancora presenti nel repository sotto "il mio progetto - copia" poiché hai copiato tutto quei file - compresi quelli sotto ... /. Git /.

Quindi hai due versioni sul tuo sistema ... puoi esaminare o copiare o modificare i file di interesse, o qualsiasi altra cosa, dal commit precedente. Puoi eliminare completamente i file in "mio progetto - copia", se hai deciso che il nuovo lavoro dal momento che il commit ripristinato non andava da nessuna parte ...

La cosa ovvia se si desidera continuare con lo stato del progetto senza effettivamente scartare il lavoro poiché questo commit recuperato è rinominare nuovamente la directory: eliminare il progetto contenente il commit recuperato (o assegnargli un nome temporaneo) e rinominare il " il mio progetto - copia la directory "torna al" mio progetto ". Quindi forse prova a capire alcune delle altre risposte qui, e probabilmente fai un altro impegno abbastanza presto.

Git è una creazione geniale ma assolutamente nessuno è in grado di "prenderlo al volo": anche le persone che cercano di spiegarlo troppo spesso assumono una conoscenza precedente di altri VCS [Version Control Systems] e approfondiscono troppo in profondità troppo presto e commettere altri crimini, come usare termini intercambiabili per "fare il check-out" - in modi che a volte sembrano quasi calcolati per confondere un principiante.

Per risparmiare molto stress, impara dalle mie cicatrici. Devi praticamente leggere un libro su Git - consiglierei "Controllo versione con Git" . Fallo prima piuttosto che dopo. Se lo fai, tieni presente che gran parte della complessità di Git proviene dalla ramificazione e quindi dal rimergere: puoi saltare quelle parti in qualsiasi libro. Dalla tua domanda non c'è motivo per cui le persone dovrebbero accecarti con la scienza .

Soprattutto se, ad esempio, questa è una situazione disperata e sei un principiante con Git!

PS: Un altro pensiero: è (ora) in realtà abbastanza semplice mantenere il repository Git in una directory diversa da quella con i file di lavoro. Ciò significherebbe che non dovresti copiare l'intero repository Git usando la soluzione rapida e sporca sopra. Vedi la risposta di Fryer usando --separate-git-dir qui . Attenzione , però: se si dispone di un repository "directory separata" che non si copia e si esegue un hard reset, tutte le versioni successive al commit di reset andranno perse per sempre, a meno che non si abbia, come si deve assolutamente, eseguiva regolarmente il backup del repository, preferibilmente su Cloud (ad es. Google Drive ) tra gli altri posti.

Su questo argomento di "backup sul cloud", il passo successivo è aprire un account (ovviamente gratuito) con GitHub o (meglio a mio avviso) GitLab . È quindi possibile eseguire regolarmente un git pushcomando per rendere il repository Cloud aggiornato "correttamente". Ma ancora una volta, parlare di questo potrebbe essere troppo presto.


23

Questo è un altro modo per ripristinare direttamente un commit recente

git stash
git stash clear

Elimina direttamente tutte le modifiche apportate dall'ultimo commit.

PS: ha un piccolo problema; elimina anche tutte le modifiche allo stash memorizzate di recente. Il che suppongo che nella maggior parte dei casi non dovrebbe importare.


NOTA: i nuovi file non aggiunti nell'indice non vengono archiviati. Li hai aggiunti troppo o li elimini manualmente.
andreyro,

Perché oh perché eliminare lo stash? Oltre ad essere una non soluzione, questo è in realtà dannoso. La lettura della prima frase della domanda invalida immediatamente la soluzione stash (che potrebbe essere utile SOLO per ripristinare il LAST commit).
Romain Valeri

22

Per pulire completamente la directory di un programmatore da alcune modifiche accidentali, abbiamo usato:

git add -A .
git reset --hard HEAD

Elimina semplicemente git reset --hard HEADle modifiche, ma non elimina i "nuovi" file. Nel loro caso avevano accidentalmente trascinato una cartella importante da qualche parte a caso, e tutti quei file venivano trattati come nuovi da Git, quindi reset --hardnon l'hanno risolto. Eseguendo in git add -A .anticipo, li ha rintracciati esplicitamente tutti con git, per essere cancellati dal reset.


21

Per mantenere le modifiche dal commit precedente a HEAD e passare al commit precedente, eseguire:

git reset <SHA>

Se non sono necessarie modifiche dal precedente commit a HEAD ed è sufficiente scartarle tutte, eseguire:

git reset --hard <SHA>

20

Credo che alcune persone potrebbero venire a questa domanda desiderando sapere come ripristinare le modifiche commesse che hanno apportato al proprio master, ovvero eliminare tutto e tornare all'origine / master, nel qual caso, fare questo:

git reset --hard origin/master

/superuser/273172/how-to-reset-master-to-origin-master


18

Ripristina è il comando per ripristinare i commit.

git revert <commit1> <commit2> 

Campione:

git revert 2h3h23233

È in grado di prendere la distanza dalla TESTA come di seguito. Qui 1 dice "ripristina l'ultimo commit".

git revert HEAD~1..HEAD

e poi fallo git push


14

Prova a ripristinare il commit desiderato -

git reset <COMMIT_ID>

(per verificare l'utilizzo di COMMIT_ID git log)

Ciò ripristinerà tutti i file modificati allo stato non aggiunto.

Ora puoi checkouttutti i file non aggiunti da

git checkout .

Controlla git logper verificare le modifiche.

AGGIORNARE

Se ne hai uno e esegui solo il commit nel tuo repository, prova

git update-ref -d HEAD


13

Man mano che i tuoi commit vengono inviati in remoto, devi rimuoverli. Lasciami supporre che il tuo ramo sia sviluppato e venga spinto oltre l' origine .

Innanzitutto è necessario rimuovere sviluppare da origine :

git push origin :develop (note the colon)

Quindi è necessario sviluppare lo stato desiderato, supponiamo che l'hash di commit sia EFGHIJK:

git reset --hard EFGHIJK

Infine, spingere di nuovo sviluppo :

git push origin develop

13

Attenzione! Questo comando può causare la perdita della cronologia di commit, se l'utente inserisce erroneamente il commit errato. Avere sempre un backup extra di Git in qualche altro posto nel caso in cui si commettano errori, di quanto si sia un po 'più sicuri. :)

Ho avuto un problema simile e volevo tornare a un commit precedente. Nel mio caso non ero interessato a mantenere il nuovo commit, quindi ho usato Hard.

Ecco come l'ho fatto:

git reset --hard CommitId && git clean -f

Questo tornerà sul repository locale e qui dopo l'uso git push -faggiornerà il repository remoto.

git push -f

13

In GitKraken puoi fare questo:

  1. Fare clic con il tasto destro del mouse sul commit che si desidera ripristinare, selezionare: Ripristina a questo commit / Hard :

    Inserisci qui la descrizione dell'immagine

  2. Fai nuovamente clic con il pulsante destro del mouse sul commit, scegli: Nome ramo corrente / Push :

    Inserisci qui la descrizione dell'immagine

  3. Fai clic su Force Push :

    Inserisci qui la descrizione dell'immagine

Obs. : È necessario fare attenzione, poiché tutta la cronologia di commit dopo il ripristino hardware viene persa e questa azione è irreversibile. Devi essere sicuro di quello che stai facendo.


11

Se si desidera correggere qualche errore nell'ultimo commit, una buona alternativa sarebbe usare il comando git commit --amend . Se l'ultimo commit non è indicato da alcun riferimento, questo farà il trucco, in quanto crea un commit con lo stesso genitore dell'ultimo commit. Se non vi è alcun riferimento all'ultimo commit, verrà semplicemente scartato e questo commit sarà l'ultimo commit. Questo è un buon modo per correggere i commit senza ripristinare i commit. Tuttavia ha i suoi limiti.

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.