Come posso annullare git reset --hard HEAD ~ 1?


1159

È possibile annullare le modifiche causate dal seguente comando? Se é cosi, come?

git reset --hard HEAD~1

8
Ho scritto una guida completa per recuperare qualsiasi commit perso con Git. Ha anche illustrazioni :-) [Dai un'occhiata] [fixLink] [fixLink]: programblings.com/2008/06/07/…
webmat

12
--hardignora le modifiche non confermate. Dato che questi non sono tracciati da Git, non c'è modo di ripristinarli tramite Git.
Zaz,


1
Questo è un ottimo articolo per aiutarti a recuperare i tuoi file.
Jan Swart,

2
Questa è una grande risorsa direttamente da Github: Come annullare (quasi) qualsiasi cosa con Git
jasonleonhard

Risposte:


1774

Pat Notz ha ragione. Puoi riavere il commit fintanto che è stato entro pochi giorni. git raccoglie solo spazzatura dopo circa un mese o meno a meno che non gli dica esplicitamente di rimuovere i nuovi BLOB.

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

Nell'esempio si può vedere che il file2 è stato rimosso a seguito del reset hardware, ma è stato rimesso a posto quando ho ripristinato tramite il reflog.


222
Puoi usare "git reset --hard HEAD @ {1}", non è necessario utilizzare SHA1. Nella maggior parte dei casi dovrebbe essere sufficiente usare "git reset --hard ORIG_HEAD".
Jakub Narębski,

39
git log -gpuò essere un modo un po 'più bello per visualizzare il reflog di git reflog.
Dan Molding,

60
C'è un avvertimento molto importante in questo .. e questa è la parte "--hard". --hard soffia via le modifiche locali non confermate. E non puoi recuperarli in questo modo (poiché non sono stati impegnati da nessuna parte). Credo che non ci sia nulla da fare al riguardo :(
Michael Anderson,

3
^ Solo così sai che puoi nascondere le tue modifiche locali prima di fare un reset --hard, e poi semplicemente pop e non perdere nulla! Devo amare git.
Lethjakman,

5
Io preferisco git reflogsopra git log -gsemplicemente perché si ottiene tutte le informazioni su una riga con sha1, informazioni HEAD e messaggi di commit tutti allineati. Molto più facile da leggere.
Snowcrash,

371

Quello che vuoi fare è specificare lo sha1 del commit che vuoi ripristinare. Puoi ottenere sha1 esaminando reflog ( git reflog) e poi facendo

git reset --hard <sha1 of desired commit>

Ma non aspettare troppo ... dopo alcune settimane git vedrà quel commit come non referenziato ed eliminerà tutti i BLOB.


2
avviso per me stesso pochi minuti fa: questo ripristinerà tutte le modifiche. tuttavia non toccherà i file non tracciati.
aexl

175

La risposta è nascosta nella risposta dettagliata sopra, puoi semplicemente fare:

$> git reset --hard HEAD@{1}

(Vedi l'output di git reflog show )


17
Nota che questa non è la soluzione se hai apportato altre modifiche al repository dopo il ripristino. Dai sicuramente un'occhiata al reflog prima di eseguire qualsiasi cosa.
forresthopkinsa,

2
Ripristina accidentalmente il mio repository, pensavo che il mio lavoro fosse perso per sempre. Questa risposta mi ha salvato la giornata.
Zaiyang Li,

woh! mi salvi davvero il giorno =)
jfcogato

Grande. Mi ha davvero aiutato.
Prashant Biradar,

117

È possibile recuperarlo se Git non ha ancora raccolto rifiuti.

Ottieni una panoramica degli impegni sospesi con fsck:

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Ripristina il commit penzolante con rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

1
Questa è roba fantastica. Vita salvata.
Mohhamad Hasham,

Una spiegazione dettagliata è disponibile qui: medium.com/@CarrieGuss/… . Roba salvavita.
tuan.dinh

49

Se sei davvero fortunato, come me, puoi tornare al tuo editor di testo e premere "annulla".

So che non è proprio una risposta corretta, ma mi ha risparmiato mezza giornata di lavoro, quindi spero che farà lo stesso per qualcun altro!


3
Questo è in realtà un ottimo suggerimento, mi ha salvato un sacco di volte;) E il suo modo più semplice di fare qualsiasi cosa in git ...
severin

3
e grazie di tutto il bene gentile in questo mondo intero. grazie. grazie. grazie.
Viaggio

9
Questo è l'unico modo per ripristinare le modifiche non messe in scena nei file dopo il ripristino hardware. Anche me mi ha salvato;)
Czarek Tomczak

4
Come suggerimento aggiuntivo, alcuni IDE come eclissi hanno anche salvato la cronologia dei file recenti. In questo modo, potresti anche essere in grado di recuperare le modifiche precedenti dopo la chiusura dell'editor. Questo ha funzionato a meraviglia per me.
martin,

1
Dio ti benedica Chris
Adam Waite,

45

per quanto ne so, --hardscarterà le modifiche non confermate. Dal momento che questi non sono seguiti da Git. ma puoi annullare il discarded commit.

$ git reflog

elenca:

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

dov'è 4bac331il discarded commit.

Ora basta spostare la testa a quel commit ::

$ git reset --hard 4bac331

34

Esempio di caso IRL:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

2
Il blob ciondolante suona come un mostro di AD&D!
sbichenko,

Grazie @Stian Ben spiegato! Vorrei aggiungere per gli altri che trovano questa risposta che se hai più di un commit "penzolante" non è sicuro che tu voglia fare un ribasso nell'ultima riga :)
JimiSweden,

git show ha salvato alcuni dei miei file, grazie mille amico!
William,

32

Nella maggior parte dei casi, sì.

A seconda dello stato in cui si trovava il repository quando è stato eseguito il comando, gli effetti git reset --hardpossono variare da banali a annullati, fino a renderli sostanzialmente impossibili.

Di seguito ho elencato una serie di diversi possibili scenari e come potresti recuperarli.

Tutti i miei cambiamenti sono stati impegnati, ma ora gli commit sono spariti!

Questa situazione si verifica in genere quando si esegue git resetcon un argomento, come in git reset --hard HEAD~. Non ti preoccupare, questo è facile da recuperare!

Se hai appena corso git resete da allora non hai fatto nient'altro, puoi tornare dove eri con questo one-liner:

git reset --hard @{1}

Questo reimposta il tuo ramo corrente in qualunque stato si trovasse prima dell'ultima modifica (nel tuo caso, la modifica più recente al ramo sarebbe l'hard reset che stai tentando di annullare).

Se, tuttavia, si avete fatto altre modifiche alla tua filiale in quanto il ripristino, l'one-liner sopra non funzionerà. Invece, dovresti eseguire per visualizzare un elenco di tutte le modifiche recenti apportate al tuo ramo (compresi i ripristini). L'elenco sarà simile al seguente:git reflog <branchname>

7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit

Trova l'operazione in questo elenco che vuoi "annullare". Nell'esempio sopra, sarebbe la prima riga, quella che dice "reset: passare a HEAD ~". Quindi copia la rappresentazione del commit prima (sotto) di quell'operazione. Nel nostro caso, ciò sarebbe master@{1}(o 3ae5027, entrambi rappresentano lo stesso commit) ed eseguiranno git reset --hard <commit>per ripristinare il ramo corrente su quel commit.

Ho messo in scena i miei cambiamenti con git add, ma non mi sono mai impegnato. Ora i miei cambiamenti sono spariti!

È un po 'più complicato recuperare. git ha avere le copie dei file aggiunti, ma dal momento che queste copie non sono mai stati legati a un particolare impegno non è possibile ripristinare le modifiche tutto in una volta. Invece, devi individuare i singoli file nel database di git e ripristinarli manualmente. Puoi farlo usandogit fsck .

Per i dettagli, vedere Annulla reset git --hard con file non impegnati nell'area di gestione temporanea .

Ho apportato modifiche ai file nella mia directory di lavoro che non ho mai messo in scena git adde che non ho mai eseguito . Ora i miei cambiamenti sono spariti!

Uh Oh. Odio dirtelo, ma probabilmente sei sfortunato. git non memorizza le modifiche che non aggiungi o ti impegni, e secondo la documentazione pergit reset :

--difficile

Reimposta l'indice e l'albero di lavoro. Qualsiasi modifica ai file tracciati nella struttura di lavoro <commit>viene scartata.

E 'possibile che si potrebbe essere in grado di recuperare le modifiche con una sorta di utilità di recupero del disco o di un servizio di recupero dati professionale, ma a questo punto che è probabilmente più problemi di quanto ne vale la pena.


1
One-liner ha funzionato per me, grazie, ma mi chiedo solo cosa faccia esattamente "@ {1}" ..
Stan Bashtavenko,

1
@StanB La documentazione è qui: git-scm.com/docs/git-rev-parse sostanzialmente si riferisce alla prima voce di reflog sul ramo corrente.
Ajedi32,

Grazie per aver coperto tutti i casi. Non avevo commesso o aggiunto il mio.
xdhmoore,

21

Se non hai ancora raccolto i rifiuti nel tuo repository (ad es. Usando git repack -do git gc, ma tieni presente che anche la garbage collection può avvenire automaticamente), il tuo commit è ancora lì - non è più raggiungibile tramite HEAD.

Puoi provare a trovare il tuo commit guardando attraverso l'output di git fsck --lost-found .

Le versioni più recenti di Git hanno qualcosa chiamato "reflog", che è un registro di tutte le modifiche apportate ai ref (al contrario delle modifiche apportate al contenuto del repository). Quindi, ad esempio, ogni volta che cambi HEAD (ovvero ogni volta che fai un git checkoutcambio di ramo) che verrà registrato. E, naturalmente, hai git resetanche manipolato HEAD, quindi è stato anche registrato. Puoi accedere agli stati più vecchi dei tuoi ref in un modo simile a quello che puoi accedere agli stati più vecchi del tuo repository, usando un @segno anziché un ~, come git reset HEAD@{1}.

Mi ci è voluto un po 'di tempo per capire qual è la differenza tra HEAD @ {1} e HEAD ~ 1, quindi ecco una piccola spiegazione:

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog

Quindi, HEAD~1significa "vai al commit prima del commit a cui HEAD attualmente punta", mentreHEAD@{1} significa "vai al commit a cui HEAD puntava prima che indicasse dove si trova attualmente".

Ciò ti consentirà facilmente di trovare il commit perso e recuperarlo.


2
Un'altra spiegazione che ritengo più chiara: HEAD ~ 1 significa andare a "genitore di HEAD", mentre HEAD @ {1} vai a "tornare indietro di un passo nella storia di HEAD"
kizzx2,

1
Il problema è che il termine "storia" è veramente sovraccarico nei VCS. Un altro modo di esprimere è che ~ va indietro nella storia del commit , mentre @ va indietro nella storia cronologica o temporale . Ma nessuna delle tre versioni è particolarmente buona.
Jörg W Mittag,

@ kizzx2 (e Jorg) in realtà quelle 3 spiegazioni, se prese insieme, aiutano molto - grazie
Richard Le Mesurier,

14

Prima di rispondere, aggiungiamo alcuni retroscena, spiegando di cosa si tratta HEAD.

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. (esclusi igit worktree )

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


detached HEAD

Se non si esegue l'ultimo commit, il che significa che HEADindica un commit precedente nella cronologia che viene chiamato detached HEAD.

inserisci qui la descrizione dell'immagine

Sulla riga di comando sarà simile a questo: 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.


git revert <sha-1>

"Annulla" l'intervallo di commit o commit specificato.
Il comando reset "annulla" tutte le modifiche apportate nel commit dato.
Verrà eseguito il commit di un nuovo commit con la patch di annullamento mentre il commit originale rimarrà anche nella cronologia.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

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

inserisci qui la descrizione dell'immagine


Sembra che il tuo git reset HEAD --hard <commit_id>esempio sia preso da stackoverflow.com/questions/4114095/… - In tal caso, potresti modificarlo nell'attribuzione?
Rob

12

git reflog

  • Trova il tuo sha sha nell'elenco, quindi copialo e incollalo in questo comando:

git cherry-pick <the sha>


1
git-cherry-pick - Applica le modifiche introdotte da alcuni commit esistenti. Penso che sia semplice e molto utile in questo contesto
Amitesh,

1
tutti lo stanno effettivamente cercando quando cercano come annullare le modifiche al ripristino forzato. questa risposta dovrebbe ottenere più
voti

@ErenL Immagino di aver appena pensato, alla gente piace fare un lavoro extra. haha
ScottyBlades,

1
Ecco, mi hai appena salvato la giornata 🙂
Sylvernus Akubo,

11

So che questo è un vecchio thread ... ma poiché molte persone sono alla ricerca di modi per annullare le cose in Git, penso ancora che possa essere una buona idea continuare a dare consigli qui.

Quando si esegue un "git add" o si sposta qualsiasi cosa dalla parte superiore sinistra a quella inferiore sinistra in git gui, il contenuto del file viene archiviato in un BLOB e il contenuto del file può essere recuperato da quel BLOB.

Quindi è possibile recuperare un file anche se non è stato eseguito il commit ma deve essere stato aggiunto.

git init  
echo hello >> test.txt  
git add test.txt  

Ora il BLOB viene creato ma a cui fa riferimento l'indice, quindi non verrà elencato con git fsck fino al ripristino. Quindi ripristiniamo ...

git reset --hard  
git fsck  

otterrai una chiazza penzolante ce013625030ba8dba906f756967f9e9ca394464a

git show ce01362  

ti restituirà il contenuto del file "ciao"

Per trovare commit senza riferimenti ho trovato un suggerimento da qualche parte che suggerisce questo.

gitk --all $(git log -g --pretty=format:%h)  

L'ho come strumento in Git Gui ed è molto utile.


+1. Come accennato in stackoverflow.com/a/21350689/6309 , git fsck --lost-foundpuò essere d'aiuto.
VonC,

7

Se si utilizza un IDE JetBrains (qualsiasi cosa basata su IntelliJ), è possibile ripristinare anche le modifiche non impegnate tramite la funzione "Cronologia locale".

Fai clic con il pulsante destro del mouse sulla directory di livello superiore nella struttura dei file, trova "Cronologia locale" nel menu di scelta rapida e scegli "Mostra cronologia". Questo aprirà una vista in cui è possibile trovare le modifiche recenti e, una volta trovata la revisione a cui vuoi tornare, fai clic destro su di essa e fai clic su "Ripristina".



3

Crea un piccolo script per rendere leggermente più facile trovare il commit che stai cercando:

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

Sì, può essere notevolmente più bello con awk o qualcosa del genere, ma è semplice e ne avevo solo bisogno. Potrebbe salvare qualcun altro 30 secondi.


0

Il mio problema è quasi simile. Ho dei file non impegnati prima di entraregit reset --hard .

Per fortuna. Sono riuscito a saltare tutte queste risorse. Dopo aver notato che posso semplicemente annullare (ctrl-z ). 😊 Voglio solo aggiungere questo a tutte le risposte sopra.

Nota. Non è possibile ctrl-zaprire file non aperti.


0

Questo mi ha salvato la vita: https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c

Fondamentalmente è necessario eseguire:

for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done

Quindi passa manualmente attraverso il dolore per riorganizzare i tuoi file nella struttura corretta.

Da asporto: non utilizzare mai git reset --hardse non si capisce completamente come funziona, meglio non usarlo.

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.