Domanda

Sto cercando di recuperare il mio lavoro.Stupidamente ho fatto git reset --hard, ma prima ho fatto solo get add . e non fare git commit.Si prega di aiutare!Ecco il mio log:

MacBookPro:api user$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)

#   modified:   .gitignore
...


MacBookPro:api user$ git reset --hard
HEAD is now at ff546fa added new strucuture for api

È possibile annullare git reset --hard in questa situazione?

È stato utile?

Soluzione

Dovresti essere in grado di recuperare tutti i file che hai aggiunto all'indice (ad esempio, come nella tua situazione, con git add .) sebbene potrebbe essere un po 'di lavoro. Per aggiungere un file all'indice, Git lo aggiunge al database degli oggetti, il che significa che può essere recuperato fintanto che la raccolta della spazzatura non è ancora avvenuta. C'è un esempio di come farlo. La risposta di Jakub Narębski qui:

Tuttavia, l'ho provato su un repository di test e ci sono stati un paio di problemi - --cached dovrebbe essere --cache, e ho scoperto che in realtà non ha creato il .git/lost-found directory. Tuttavia, i seguenti passaggi hanno funzionato per me:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")

Ciò dovrebbe produrre tutti gli oggetti nel database degli oggetti che non sono raggiungibili da alcun Rif, nell'indice o tramite il riflesso. L'output sembrerà qualcosa di simile:

unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03

... e per ciascuna di quelle macchie, puoi fare:

git show 907b308

Per eliminare il contenuto del file.


Troppa output?

Aggiornamento in risposta a SeheIl commento di seguito:

Se scopri di avere molti commit e alberi elencati nell'output di quel comando, potresti voler rimuovere dall'output eventuali oggetti a cui si fa riferimento da commit non riferenziati. (In genere è possibile tornare a questi commit tramite il riflesso - siamo solo interessati agli oggetti che sono stati aggiunti all'indice ma non ci possono mai essere trovati tramite un commit.)

Innanzitutto, salva l'output del comando, con:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all

Ora i nomi degli oggetti di quei commit irraggiungibili possono essere trovati con:

egrep commit all | cut -d ' ' -f 3

Quindi puoi trovare solo gli alberi e gli oggetti che sono stati aggiunti all'indice, ma non commessi in nessun momento, con:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \
  $(egrep commit all | cut -d ' ' -f 3)

Ciò riduce enormemente il numero di oggetti che dovrai considerare.


Aggiornare: Philip Oakley di seguito suggerisce un altro modo per ridurre il numero di oggetti da considerare, che è quello di considerare i file modificati più recentemente sotto .git/objects. Puoi trovarli con:

find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort

(L'ho trovato find invocazione qui.) La fine di quell'elenco potrebbe apparire:

2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b
2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a

In tal caso puoi vedere quegli oggetti con:

git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b
git show de629830603289ef159268f443da79968360913a

(Nota che è necessario rimuovere il / Alla fine del percorso per ottenere il nome dell'oggetto.)

Altri suggerimenti

Ho appena fatto un reset git -hard e ho perso un commit. Ma conoscevo il commit hash, quindi sono stato in grado di farlo Git Cherry-Pick commit_hash per ripristinarlo.

L'ho fatto in pochi minuti dalla perdita del commit, quindi potrebbe funzionare per alcuni di voi.

Grazie a Mark Longair ho recuperato le mie cose!

Per prima cosa ho salvato tutti gli hash in un file:

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes

Successivamente li metto tutti (rimuovendo la cosa "non raggiungibile") in un elenco e metto i dati tutti in nuovi file ... devi scegliere i tuoi file e rinominarli di nuovo di cui hai bisogno ... ma ne avevo solo bisogno di alcuni Files..Pepe questo aiuta qualcuno ...

commits = ["c2520e04839c05505ef17f985a49ffd42809f",
    "41901be74651829d97f29934f190055ae4e93",
    "50f078c937f07b508a1a73d3566a822927a57",
    "51077d43a3ed6333c8a3616412c9b3b0fb6d4",
    "56e290dc0aaa20e64702357b340d397213cb",
    "5b731d988cfb24500842ec5df84d3e1950c87",
    "9c438e09cf759bf84e109a2f0c18520",
    ...
    ]

from subprocess import call
filename = "file"
i = 1
for c in commits:
    f = open(filename + str(i),"wb")
    call(["git", "show", c],stdout=f)
    i+=1

@Ajedi32 la soluzione nei commenti per me ha funzionato esattamente in questa situazione.

git reset --hard @{1}

Si noti che tutte queste soluzioni si basano sul fatto che non esistono git gc, e alcuni di loro potrebbe causare uno, quindi mi piacerebbe zip backup del contenuto del vostro .git directory prima di provare qualsiasi cosa, in modo che si dispone di uno snapshot di tornare indietro se non funziona per voi.

Ha riscontrato lo stesso problema, ma non aveva aggiunto le modifiche all'indice. Quindi tutti i comandi sopra non mi hanno riportato le modifiche desiderate.

Dopo tutte le risposte elaborate di cui sopra, questo è un suggerimento ingenuo, ma può essere salvare qualcuno che non ci ha pensato prima, come ho fatto io.

In disperazione, ho provato a premere Ctrl-Z nel mio editor (LightTable), una volta in ogni scheda aperta-questo fortunatamente ha recuperato il file in quella scheda, nel suo ultimo stato davanti al git reset --hard. Hth.

Bontà, mi sono tirato i capelli fino a quando non ho incontrato questa domanda e le sue risposte. Credo che la risposta corretta e succinta alla domanda posta sia disponibile solo se tiri due dei commenti sopra insieme, quindi eccolo tutto in un unico posto:

  1. Come menzionato da Chilicuil, esegui "Git Reflog" per identificare lì il commit hash a cui vuoi tornare

  2. Come menzionato da Akimsko, probabilmente non vorrai scegliere la ciliegia a meno che tu non abbia perso solo un commit, quindi dovresti quindi eseguire 'git reset -hard

Nota per gli utenti EGIT Eclipse: non sono riuscito a trovare un modo per fare questi passaggi all'interno di Eclipse con EGIT. La chiusura di Eclipse, eseguendo i comandi sopra da una finestra del terminale, quindi riaprire Eclipse ha funzionato bene per me.

Questo è probabilmente ovvio per i professionisti GIT là fuori, ma volevo metterlo da quando nella mia frenetica ricerca non ho visto questo sollevato.

Ho messo in scena alcuni file e ho resorizzato un po 'di ripristino del Git, ho impazzito un po' e poi ho notato che il mio stato ha mostrato che tutti i miei file sono ancora messi in scena e tutte le loro eliminazioni non messe in scena.

A questo punto puoi commettere quei cambiamenti in scena, purché non metti in scena le loro eliminazioni. Dopo questo, devi solo elaborare il coraggio di fare ancora una volta "Git Reset -Hard", il che ti riporterà a quei cambiamenti che avevi messo in scena e ora ti impegnerà.

Ancora una volta, questo probabilmente non è una novità per la maggior parte, ma spero che dal momento che mi ha aiutato e non ho trovato nulla che lo suggerisca, potrebbe aiutare qualcun altro.

Le soluzioni di cui sopra possono funzionare, tuttavia, ci sono modi più semplici per riprendersi da questo invece di passare git-S Complesso Annulla. Immagino che la maggior parte delle rese Git si verificano su un numero limitato di file e, se usi già VIM, questa potrebbe essere la soluzione più efficiente nel tempo. L'avvertenza è che devi già usare ViM's persistente-indotto, che dovresti usare in entrambi i modi, perché ti fornisce la possibilità di annullare il numero illimitato di modifiche.

Ecco i passaggi:

  1. In Vim Press : e digita il comando set undodir. Se hai persistent undo acceso nel tuo .vimrc, mostrerà un risultato simile aundodir=~/.vim_runtime/temp_dirs/undodir.

  2. Nel tuo Repo Use git log Per scoprire l'ultima data/ora che hai fatto l'ultima commissione

  3. Nella tua shell naviga sul tuo undodir usandocd ~/.vim_runtime/temp_dirs/undodir.

  4. In questa directory usa questo comando per trovare tutti i file che hai cambiato dall'ultimo commit

    find . -newermt "2018-03-20 11:24:44" \! -newermt "2018-03-23" \( -type f -regextype posix-extended -regex '.*' \) \-not -path "*/env/*" -not -path "*/.git/*"

    Qui "2018-03-20 11:24:44" è la data e l'ora dell'ultimo commit. Se la data in cui hai fatto il git reset --hard è "2018-03-22", quindi usa "2018-03-22", quindi usa "2018-03-23". Ciò è dovuto a una stranezza di scoperta, in cui il limite inferiore è inclusivo e il limite superiore è esclusivo.https://unix.stackexchange.com/a/70404/242983

  5. Quindi vai a ciascuno dei file aprili in VIM e fai un "20m precedenti". Puoi trovare maggiori dettagli su "prima" usando "H prima". Quiearlier 20m significa tornare allo stato del file 20 minuti fa, supponendo che tu abbia fatto il git hard --reset, 20 minuti fa. Ripeti su tutti i file che sono stati sputati da find comando. Sono sicuro che qualcuno può scrivere una sceneggiatura che combinerà queste cose.

Sto usando Intellij e sono stato in grado di passare semplicemente ogni file e fare:

Edit -> reload from disk

Fortunatamente, avevo appena fatto un git status Proprio prima di spazzare via i miei cambiamenti di lavoro, quindi sapevo esattamente cosa dovevo ricaricare.

Ricordare la tua gerarchia dei file e l'uso della tecnica di Mark Longair con la modifica di Phil Oakley produce risultati drammatici.

Essenzialmente se hai almeno aggiunto i file al repository ma non lo hai impegnato, puoi ripristinare in modo interattivo usando "Git Show", ispezionare il registro e utilizzare il reindirizzamento della shell per creare ogni file (ricordando il tuo percorso di interesse).

Hth!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top