Posso recuperare una filiale dopo la sua cancellazione in Git?


1068

Se corro git branch -d XYZ, c'è un modo per recuperare il ramo? C'è un modo per tornare indietro come se non avessi eseguito il comando delete branch?


4
Una nota davvero fantastica da fare sulla risposta accettata è che funziona anche se il ramo è stato cancellato in origine! Ho appena recuperato diversi rami che non avevo più localmente dopo che erano stati accidentalmente cancellati in origine.
theblang

Risposte:


1955

Sì, dovresti essere in grado di fare git refloge trovare SHA1 per il commit sulla punta del tuo ramo eliminato, quindi solo git checkout [sha]. E una volta che sei a quel commit, puoi semplicemente git checkout -b [branchname]ricreare il ramo da lì.


Ringraziamo @Cascabel per questa versione ridotta / one-liner.

Puoi farlo in un solo passaggio:

git checkout -b <branch> <sha>

477
Lo si può fare in un solo passaggio: git checkout -b <branch> <sha>.
Cascabel,

200
Suggerimento rapido: se hai appena eliminato il ramo vedrai qualcosa del genere nel tuo terminale: "Ramo eliminato <il tuo ramo> (era <sha>)". E poi è semplicissimo: basta usarlo <sha>. Ad esempio, come menzionato sopra -git checkout -b <branch> <sha>
Snowcrash,

6
sì, scorri verso l'alto nel tuo terminale (a meno che tu non l'abbia fatto CMD+K)
neaumusica

42
Utilizzare git reflog --no-abbrevper vedere il completo <sha>abbreviato per impostazione predefinita.
jkulak,

5
Per chiunque altro come me, che ha avuto problemi a trovare lo sha del ramo eliminato: sono stato in grado di farlo git checkout remotes/origin/deleted_branch.
Jeff Irwin,

161

La maggior parte delle volte i commit non raggiungibili sono nel reflog. Quindi, la prima cosa da provare è guardare il reflog usando il comando git reflog(che mostra il reflog per HEAD).

Forse qualcosa di più semplice se il commit fosse parte di un ramo specifico ancora esistente è usare il comando git reflog name-of-my-branch . Funziona anche con un telecomando, ad esempio se hai forzato la spinta (consiglio aggiuntivo: preferisci sempregit push --force-with-lease piuttosto prevenire meglio errori ed è più recuperabile).


Se i tuoi commit non sono nel tuo reflog (forse perché cancellati da uno strumento di terze parti che non scrive nel reflog), ho recuperato con successo un ramo resettando il mio ramo allo sha del commit trovato usando un comando come quello (esso crea un file con tutti i commit sospesi):

git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

Se dovessi usarlo più di una volta (o vuoi salvarlo da qualche parte), potresti anche creare un alias con quel comando ...

git config --global alias.rescue '!git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt'

e usalo con git rescue

Per esaminare i commit trovati, è possibile visualizzare ciascun commit utilizzando alcuni comandi per esaminarli.

Per visualizzare i metadati di commit (autore, data di creazione e messaggio di commit):

git cat-file -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Per vedere anche le differenze:

git log -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Una volta trovato il commit, quindi creare un ramo su questo commit con:

git branch commit_rescued 48540dfa438ad8e442b18e57a5a255c0ecad0560

Per quelli che si trovano in Windows e amano le GUI, puoi facilmente recuperare i commit (e anche i file in staging senza commit) con GitExtensions utilizzando la funzione Repository=>Git maintenance =>Recover lost objects...


Un comando simile per recuperare facilmente i file in fasi eliminati: https://stackoverflow.com/a/58853981/717372


2
Enorme aiuto. Ho perso un commit che non è mai stato nel mio repository locale. Il primo comando che hai lassù mi ha aiutato a trovarlo sul server. +1
Sean Adkinson,

1
che git rescue alias è una manna dal cielo !!! Grazie mille per aver contribuito!
72A12F4E,

2
Mi hai salvato la vita.
Jed Lynch,

La risposta di Patrick Koorevaar mi ha aiutato, perché non conosco i miei ultimi commit ramificati cancellati <sha>.
Monir Khan,

@ Monir-Khan And? Cosa dovrei concludere? La risposta di Patrick è solo una copia / incolla del mio comando (con un errore: ha dimenticato di filtrare i commit) ...
Philippe

45

Se ti piace usare una GUI, puoi eseguire l'intera operazione con gitk.

gitk --reflog

Ciò ti consentirà di visualizzare la cronologia di commit del ramo come se il ramo non fosse stato eliminato. Ora fai semplicemente clic con il pulsante destro del mouse sul commit più recente per il ramo e seleziona l'opzione di menu Create new branch.


28

La soluzione più votata in realtà fa più di quanto richiesto:

git checkout <sha>
git checkout -b <branch>

o

git checkout -b <branch> <sha>

spostarti nella nuova filiale insieme a tutte le modifiche recenti che potresti aver dimenticato di impegnare. Questa potrebbe non essere la tua intenzione, specialmente quando sei in "modalità panico" dopo aver perso il ramo.

Una soluzione più pulita (e più semplice) sembra essere quella di una linea (dopo aver trovato il <sha>con git reflog):

git branch <branch> <sha>

Ora non sono interessati né il ramo corrente né le modifiche non impegnate. Invece verrà creato solo un nuovo ramo fino al<sha> .

Se non è la punta, funzionerà comunque e otterrai un ramo più corto, quindi puoi riprovare con nuovo <sha> nome di ramo e nuovo fino a quando non lo ottieni nel modo giusto.

Finalmente puoi rinominare il ramo ripristinato con successo in come è stato chiamato o in qualsiasi altra cosa:

git branch -m <restored branch> <final branch>

Inutile dire che la chiave del successo era trovare il giusto commit <sha>, quindi dai un nome saggio ai tuoi commit :)


14

Aggiungendo alla risposta tfe : c'è anche lo script git-resurrect.shcontrib/ nell'area delle fonti Git (nel repository git.git), che potrebbe aiutarti.

git-resurrect <name>tenta di trovare tracce di un ramo chiamato <name>e cerca di resuscitarlo. Attualmente, il reflog viene cercato per i messaggi di checkout e -ranche per unire i messaggi. Con -me -t, la storia di tutti i riferimenti viene scansionata per Merge <name> into other/ Merge <other> into <name>(rispettivamente) impegnare soggetti, che è piuttosto lento ma consente di resuscitare rami di argomenti di altre persone.


1
Ora ha funzionato per me anche se ho dovuto aggiungere / usr / lib / git-core / al mio PERCORSO. Ma non ha compiuto il miracolo che speravo :(
Amanic,

10

Ho usato i seguenti comandi per trovare e recuperare il mio ramo cancellato. I primi passi sono dalla descrizione di gcb.

$ git fsck --full --no-reflogs --unreachable --lost-found > lost
$ cat lost | cut -d\  -f3 > commits
$ cat commits | xargs -n 1 git log -n 1 --pretty=oneline

Ora cerca l'id di commit git (GIT-SHA) in base ai commenti di commit e usalo nel comando seguente. Acquista una nuova filiale chiamata NEW-BRANCH con il GIT-SHA precedentemente trovato:

$ git checkout -b NEW-BRANCH GIT-SHA

Grazie mille. Ci è voluto un po 'di tempo per cercare il nome, ma ne è valsa la pena. Se c'è un modo per cercare anche sulla stringa di messaggi di commit, sarebbe molto meglio.
Monir Khan,

9

Se non si dispone di un reflog, ad es. poiché stai lavorando in un repository nudo che non ha il reflog abilitato e il commit che vuoi recuperare è stato creato di recente, un'altra opzione è quella di trovare oggetti commit creati di recente e guardarli.

Dall'interno della .git/objectsdirectory eseguire:

find . -ctime -12h -type f | sed 's/[./]//g' | git cat-file --batch-check | grep commit

Trova tutti gli oggetti (commit, file, tag ecc.) Creati nelle ultime 12 ore e li filtra per mostrare solo i commit. Il controllo di questi è quindi un processo rapido.

Tuttavia, proverei prima lo script git-ressurect.sh menzionato nella risposta di Jakub .


1
Bella idea alternativa! Il tuo comando genera comunque un errore. Il problema è con la parte "12h" (in realtà la "h"). Una volta rimossa la "h" ha funzionato bene. Da man find: "-ctime n - Lo stato del file è stato modificato l'ultima volta n * 24 ore fa." Quindi dovremmo anche cambiare da 12 a 0,5 per avere il comportamento previsto delle ultime 12 ore.
pagliuca,

1
Sto usando OS X 10.8 qui, quindi i flag 'trova' sopra si basano sulla versione fornita.
Robert Knight,

1
Sì, certo che il problema riguarda le versioni! Ecco perché ho valutato la tua risposta al primo posto! Ho appena commentato, quindi le persone si rendono conto che i parametri potrebbero essere diversi.
pagliuca,

9

Per gli utenti GitHub senza Git installato:

Se si desidera ripristinarlo dal sito Web GitHub , è possibile utilizzare la loro API per ottenere un elenco di eventi relativi al repository:

Primo

  • trova quegli SHA (commit hash):

    curl -i https://api.github.com/repos/PublicUser/PublicRepo/events

    ... o per repository privati:

    curl -su YourUserName https://api.github.com/repos/YourUserName/YourProject/events

    (verrà richiesta la password GitHub)

    • (Se il repo richiede un'autorizzazione a due fattori, vedere i commenti su questa risposta di seguito.)

Il prossimo

  • vai su GitHub e crea un nuovo ramo temporaneo che verrà eliminato per sempre ( Chrome è preferibile).

   • Vai ai rami ed elimina quello.

   •   Nella stessa pagina, senza ricaricare , aprire DevTools, pannello Rete. Ora prepara ...

   • Fai clic su Ripristina. Noterai una nuova "linea". Fai clic destro su di esso e seleziona "Copia come cURL" e salva questo testo in alcuni editor.

   • aggiungere alla fine della riga copiata di codice, questo: -H "Cookie=".

Ora dovresti ottenere qualcosa del tipo:

    curl 'https://github.com/UserName/ProjectName/branches?branch=BranchSHA&name=BranchName' -H 'Cookie:' -H 'Origin: https://github.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US' -H 'User-Agent: User-Agent' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Accept: */*' -H 'Referer: https://github.com/UserName/ProjectName/branches' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' --data 'utf8=%E2%9C%93&authenticity_token=token' --compressed

Passo finale

  • sostituisci "BranchSHA" con il tuo SHA-hash e BranchName con il nome desiderato (A proposito, è un grande trucco rinominare il ramo dal web). Se non eri troppo lento, devi comunque fare questa richiesta. Ad esempio, basta copiare e incollare su un terminale.

PS

Mi rendo conto che questa potrebbe non essere la "soluzione più semplice" o la "giusta" soluzione, ma viene offerta nel caso in cui qualcuno la trovi utile.


1
Quanto sopra è uno dei pochi là fuori che non fa affidamento git refloge quindi è stato utile, ad esempio, quando si è cancellato un ramo remoto e si è perso l'accesso al computer che è stato fatto in modo da non ottenere nulla di freddo utile reflog. Nota quando usi OAuth o l'autenticazione a due fattori su Github il curlcomando diventa nel seguente modo: curl -u username:token https://api.github.com/useroppurecurl -H "Authorization: token TOKEN" https://api.github.com/repos/USER_OR_ORG_NAME/REPO_NAME/events
TT--

@ TT-- wow, sono contento che abbia aiutato! e grazie per il tuo contributo in merito al token di autenticazione :)
Maxim Mazurok,

8

Dalla mia comprensione se il ramo da eliminare può essere raggiunto da un altro ramo, è possibile eliminarlo in modo sicuro utilizzando

git branch -d [branch]

e il tuo lavoro non è perso. Ricorda che un ramo non è un'istantanea, ma un puntatore a uno. Quindi quando elimini un ramo elimini un puntatore.

Non perderai nemmeno lavoro se elimini un ramo che non può essere raggiunto da un altro. Ovviamente non sarà facile come controllare l'hash di commit, ma puoi ancora farlo. Ecco perché Git non è in grado di eliminare un ramo che non è possibile raggiungere utilizzando -d. Invece devi usare

git branch -D [branch]

Questo fa parte di un must per guardare il video di Scott Chacon su Git. Controlla il minuto 58:00 quando parla dei rami e di come eliminarli.

Introduzione a Git con Scott Chacon di GitHub


7
In che modo aiuta a rispondere alla domanda?
Dmitri Zaitsev,

6
Dire chi si chiede che i rami non contengano contenuti ma che in realtà siano puntatori. Non devi aver paura di eliminare i rami .. puoi crearne di nuovi puntando allo stesso commit di quello cancellato .... Caspita! Ricordo ancora quando ho posto questa domanda. Bei tempi al 2012!
fabiopagoti,

1
Ho dovuto scorrere tre schermate fino a ULTIMO per trovare una risposta che risolva il problema: eliminare un ramo significa eliminare un semplice puntatore. Nessuna situazione di perdita di dati qui, l'unica cosa da recuperare è dove stava puntando. Le risposte che arrivano direttamente reflogsono semplicemente eccessive.
Romain Valeri,

5

Assicurati di eseguire tutto ciò localmente e verifica che il tuo repository sia nello stato desiderato prima di inviare a Bitbucket Cloud. Potrebbe anche essere una buona idea clonare l'attuale repository e testare prima queste soluzioni.

  1. Se hai appena eliminato il ramo, vedrai qualcosa di simile nel tuo terminale:
    Deleted branch <your-branch> (was <sha>)

2.Per ripristinare il ramo, utilizzare:

    git checkout -b <branch> <sha>

Se non conosci lo "sha" dalla parte superiore della testa, puoi:

  1. Trova lo 'sha' per il commit sulla punta del tuo ramo cancellato usando:
    git reflog
  1. Per ripristinare il ramo, utilizzare:
    git checkout -b <branch> <sha>

Se i tuoi commit non sono nel tuo reflog:

  1. Puoi provare a ripristinare un ramo reimpostando il ramo sullo sha del commit trovato usando un comando come:
    git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

2.È quindi possibile visualizzare ciascun commit utilizzando uno di questi:

    git log -p <commit>
    git cat-file -p <commit>

4

Per recuperare un ramo cancellato, per prima cosa consulta la cronologia dei reflog,

git reflog -n 60

Dove n si riferisce agli ultimi n si impegna. Quindi trova la testa corretta e crea un ramo con quella testa.

git branch testbranch HEAD@{30}

4

Ho riassemblato un ramo da remoto per cercare di cancellare alcuni impegni che non volevo e avrei cercato di scegliere quelli giusti che volevo. Naturalmente ho sbagliato a scrivere gli SHA ...

Ecco come li ho trovati (principalmente un'interfaccia / interazione più semplice dalle cose sulle risposte qui):

Innanzitutto, genera un elenco di commit non registrati nel registro. Fallo il prima possibile e smetti di funzionare, poiché potrebbero essere scaricati dal garbage collector.

git fsck --full --no-reflogs --unreachable --lost-found > lost

Questo crea un lostfile con tutti i commit che dovrai osservare. Per semplificare la nostra vita, tagliamo solo lo SHA da esso:

cat lost | cut -d\  -f3 > commits

Ora hai un commitsfile con tutti i commit che devi guardare.

Supponendo che tu stia usando Bash, il passaggio finale:

for c in `cat commits`; do  git show $c; read; done

Questo ti mostrerà le informazioni di diff e commit per ognuna di esse. E aspetta che tu prema Enter. Ora scrivi tutti quelli che vuoi e poi selezionali. Dopo aver finito, basta premere Ctrl-C.



1

Per prima cosa vai in git batch per passare al tuo progetto come:

cd android studio project
cd Myproject
then type :
git reflog

Tutti voi avete un elenco delle modifiche e il numero di riferimento prende il numero di riferimento, quindi fate il checkout
da Android Studio o dal Git Betcha. un'altra soluzione prende il numero di riferimento e vai su android studio fai clic sui rami git verso il basso, quindi fai clic sul tag checkout o sulla revisione oltre il numero di riferimento, quindi lol hai i rami.


1

Aggiungendo alla risposta di tfe, è possibile recuperare con questo processo menzionato, a meno che i suoi commit non siano garbage collection. Il ramo Git è semplicemente un puntatore a un particolare commit nella struttura di commit. Ma se si elimina il puntatore e i commit su quel ramo non vengono uniti in un altro ramo esistente, git lo considera come commit penzolanti e li rimuove durante la garbage collection, che può essere eseguita automaticamente periodicamente.

Se il tuo ramo non è stato unito a un ramo esistente e se è stata raccolta rifiuti, perderai tutti i commit fino al punto in cui il ramo è stato biforcato da un ramo esistente.


1

Un problema correlato: sono arrivato a questa pagina dopo aver cercato "come sapere quali sono i rami eliminati".

Durante l'eliminazione di molti rami vecchi, ho sentito di aver erroneamente cancellato uno dei rami più recenti, ma non conoscevo il nome per recuperarlo.

Per sapere quali rami sono stati eliminati di recente, procedi come segue:

Se vai al tuo URL Git, che sarà simile a questo:

https://your-website-name/orgs/your-org-name/dashboard

Quindi puoi vedere il feed, di ciò che viene eliminato, da chi, nel recente passato.


Sicuro. La risposta sopra è per GitHub. Abbiamo installato GitHub localmente. Grazie per aver posto la domanda.
Manohar Reddy Poreddy

1

L'ho fatto sul computer che elimino il ramo:

git reflog

risposta:

74b2383 (develope) HEAD@{1}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: checkout: moving from develope to master
74b2383 (develope) HEAD@{3}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{4}: reset: moving to HEAD
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{5}: clone: from http://LOCALGITSERVER/myBigProject/Android.git

e recupero il ramo con questo comando:

git checkout -b newBranchName 74b2383


0

Il solo utilizzo git reflognon ha restituito il valore shaper me. Solo il commit id(che è lungo 8 caratteri e uno sha è molto più lungo)

Quindi ho usato git reflog --no-abbrev

E poi fai lo stesso come menzionato sopra: git checkout -b <branch> <sha>


puoi sempre usare lo sha di 8 caratteri abbreviato, non devi usare lo sha completo
Michael Dreher,

0

SE stai usando VSCode ... e hai sincronizzato il tuo ramo con il server ad un certo punto prima di eliminarlo ...

Si noti che git branch delete elimina solo la copia locale, non la copia sul server. Innanzitutto, nel pannello Git (icona git sulla barra degli strumenti a sinistra), guarda tra i rami e vedi se il tuo ramo è ancora lì sotto "origine / nome_branco". In tal caso, selezionalo e dovresti recuperare il tuo codice (suggerisci di copiarlo / incollarlo / salvarlo localmente da qualche altra parte).

Se non hai visualizzato "origin / your_branch_name", installa l'estensione GitLens. Ciò consente di cercare visivamente nei repository del server e di individuare la copia sincronizzata con il server. Se hai più repository, tieni presente che potrebbe essere necessario aprire almeno un file dal repository desiderato per far apparire il repository in GitLens. Poi:

  1. Apri il pannello GitLens

  2. Espandi il repository

  3. Dovresti vedere un elenco di categorie: Filiali / Collaboratori / Telecomandi / Stash / ecc

Dovresti trovare YourLostTreasure in "Filiali" o possibilmente in "Telecomandi -> Origini". Speriamo che vedrai un ramo con il nome desiderato - se lo espandi, dovresti vedere i file che hai cambiato in quel ramo. Fare doppio clic sui nomi dei file per aprirli e eseguire immediatamente il backup di quel codice.

Se non vedi immediatamente il tuo ramo perduto, cerca e se trovi qualcosa di promettente, aprilo immediatamente e prendi il codice. Ho dovuto curiosare un po 'fino a quando non ho trovato TheGoldenBranch, e anche allora il codice mancava l'ultimo o due salvataggi (forse perché non sono riuscito a sincronizzare con il server prima di provare a-Branch-Merge-ma-accidentalmente-clic- Branch-Delete). La mia ricerca è stata inutilmente allungata perché quando ho trovato il ramo per la prima volta non ero completamente sicuro che il nome fosse corretto, quindi continuavo a cercare e ci è voluto del tempo per ritrovare quel primo ramo. (Quindi, Carpe Carpum e poi continua a cercare.)

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.