È possibile annullare le modifiche causate dal seguente comando? Se é cosi, come?
git reset --hard HEAD~1
--hard
ignora le modifiche non confermate. Dato che questi non sono tracciati da Git, non c'è modo di ripristinarli tramite Git.
È possibile annullare le modifiche causate dal seguente comando? Se é cosi, come?
git reset --hard HEAD~1
--hard
ignora le modifiche non confermate. Dato che questi non sono tracciati da Git, non c'è modo di ripristinarli tramite Git.
Risposte:
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.
git log -g
può essere un modo un po 'più bello per visualizzare il reflog di git reflog
.
git reflog
sopra git log -g
semplicemente perché si ottiene tutte le informazioni su una riga con sha1, informazioni HEAD e messaggi di commit tutti allineati. Molto più facile da leggere.
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.
La risposta è nascosta nella risposta dettagliata sopra, puoi semplicemente fare:
$> git reset --hard HEAD@{1}
(Vedi l'output di git reflog show )
È 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
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!
per quanto ne so, --hard
scarterà 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'è 4bac331
il discarded commit
.
Ora basta spostare la testa a quel commit ::
$ git reset --hard 4bac331
$ 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.
A seconda dello stato in cui si trovava il repository quando è stato eseguito il comando, gli effetti git reset --hard
possono variare da banali a annullati, fino a renderli sostanzialmente impossibili.
Di seguito ho elencato una serie di diversi possibili scenari e come potresti recuperarli.
Questa situazione si verifica in genere quando si esegue git reset
con un argomento, come in git reset --hard HEAD~
. Non ti preoccupare, questo è facile da recuperare!
Se hai appena corso git reset
e 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.
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 .
git add
e 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.
Se non hai ancora raccolto i rifiuti nel tuo repository (ad es. Usando git repack -d
o 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 checkout
cambio di ramo) che verrà registrato. E, naturalmente, hai git reset
anche 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~1
significa "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.
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 HEAD
in qualsiasi momento. (esclusi igit worktree
)
Il contenuto di HEAD
è memorizzato all'interno .git/HEAD
e contiene i 40 byte SHA-1 del commit corrente.
detached HEAD
Se non si esegue l'ultimo commit, il che significa che HEAD
indica un commit precedente nella cronologia che viene chiamato detached HEAD
.
Sulla riga di comando sarà simile a questo: SHA-1 invece del nome del ramo poiché HEAD
non punta alla punta del ramo corrente
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 reflog
anche quello.
git reflog
visualizzerà qualsiasi modifica che ha aggiornato il HEAD
e il checkout della voce di reflog desiderata HEAD
riporterà 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
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.
git rebase --no-autostash
anche 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 && checkout
modifica il HEAD
.
git reset HEAD --hard <commit_id>
esempio sia preso da stackoverflow.com/questions/4114095/… - In tal caso, potresti modificarlo nell'attribuzione?
git reflog
git cherry-pick <the sha>
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.
git fsck --lost-found
può essere d'aiuto.
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".
Ho appena effettuato un hard reset su un progetto sbagliato. Ciò che mi ha salvato la vita è stata la storia locale di Eclipse. Si dice che anche IntelliJ Idea ne abbia uno, e così anche il tuo editor, vale la pena controllare:
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.
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-z
aprire file non aperti.
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 --hard
se non si capisce completamente come funziona, meglio non usarlo.