Git: recupera il ramo (remoto) eliminato


94

Devo recuperare due rami Git che in qualche modo ho cancellato durante un push.

Questi due rami sono stati creati su un sistema diverso e quindi inviati al mio repository "condiviso" (github).

Sul mio sistema, ho (apparentemente) recuperato i rami durante un recupero:

~/myfolder> git fetch
remote: Counting objects: 105, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 62 (delta 29), reused 0 (delta 0)
Unpacking objects: 100% (62/62), done.
From github.com:mygiturl
 * [new branch]      contact_page -> origin/contact_page
   731d1bb..e8b68cc  homepage   -> origin/homepage
 * [new branch]      new_pictures -> origin/new_pictures

Subito dopo ho fatto una spinta per inviare le mie modifiche locali al repository centrale. Per qualche motivo, questi rami sono stati eliminati sia dal mio sistema locale che dal repository centrale:

~/myfolder> git push
Counting objects: 71, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (43/43), done.
Writing objects: 100% (49/49), 4.99 KiB, done.
Total 49 (delta 33), reused 0 (delta 0)
To git@github.com:mygiturl.git
 - [deleted]         contact_page
 + e8b68cc...731d1bb homepage -> homepage (forced update)
   bb7e9f2..e0d061c  master -> master
 - [deleted]         new_pictures
   e38ac2e..bb7e9f2  origin/HEAD -> origin/HEAD
   731d1bb..e8b68cc  origin/homepage -> origin/homepage
   e38ac2e..bb7e9f2  origin/master -> origin/master
 * [new branch]      origin/contact_page -> origin/contact_page
 * [new branch]      origin/new_pictures -> origin/new_pictures

Non è molto facile staccare i rami dalla loro macchina del luogo di nascita, quindi vorrei provare a recuperarli dal mio locale, se possibile.

Tutte le informazioni di "annullamento" di git che ho cercato su Google hanno a che fare con il recupero dei commit persi. Non penso che ciò si applichi qui, dal momento che non ho UID di commit per questi rami.

Vorrei sapere come posso riaverli indietro. Mi piacerebbe anche sapere come sono stati eliminati in primo luogo e come posso evitarlo in futuro.

EDIT: su richiesta, ecco la mia configurazione repo

user.name=Craig Walker
user.email=github@softcraft.ca
alias.unadd=reset HEAD
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
remote.origin.url=git@github.com:MyGitURL.git
remote.origin.mirror=true
branch.master.remote=origin
branch.master.merge=refs/heads/master
alias.undo=reset --hard
alias.test=push -f ci HEAD:master
alias.st=status
alias.ci=commit
alias.br=branch
alias.co=checkout
alias.ch=checkout
alias.df=diff
alias.lg=log -p
alias.who=shortlog -s --
remote.ci.url=ContinuousIntegrationGitURL
remote.ci.fetch=+refs/heads/*:refs/remotes/ci/*
branch.photo.remote=origin
branch.photo.merge=refs/heads/photos
remote.foo.url=FooGitURL
remote.foo.fetch=+refs/heads/*:refs/remotes/cynthia/*
branch.homepage.remote=origin
branch.homepage.merge=refs/heads/homepage

Sembra che tu abbia una configurazione di recupero e invio "insolita" o non corrispondente. Cosa git config -lmostra per il repository locale?
CB Bailey

Molto probabilmente; L'ho postato.
Craig Walker

2
Il tuo remote.origin.fetchrefspec non è appropriato per l'uso con remote.origin.mirror = true. Vuoi eseguire il mirroring o vuoi utilizzare il repository GitHub come un normale telecomando? La mia risposta dovrebbe contenere i comandi di cui hai bisogno in entrambi i casi.
Chris Johnsen

Immagino che con il secondo repository, il mirroring non sia più un'opzione (questo probabilmente ha causato l'eliminazione in primo luogo).
Craig Walker

Risposte:


103

Non sono un esperto Ma puoi provare

git fsck --full --no-reflogs | grep commit

per trovare il commit HEAD del ramo cancellato e recuperarli.


Ho provato fsck prima; sai come scoprire quale commit è quello corretto? Ne ho 20 da provare.
Craig Walker

1
Questo lo ha fatto; una volta ricevuti i messaggi di commit, git branch <uid>li ho recuperati. Grazie!
Craig Walker

Buono a sapersi. Assicurati di risolvere anche il conflitto tra le tue impostazioni remotes.origin.mirrore remotes.origin.fetch, altrimenti sei destinato a incappare di nuovo nel problema (o involontariamente clobber commit spinti da altri repository).
Chris Johnsen

@ Craig: Felice di essere d'aiuto :)
iamamac

3
Oggi ho perso un ramo di release candidate. Non conoscevo l'ID commit. Ottenuto recuperato utilizzando:git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
spezifanta

23

solo due comandi mi salvano la vita

1. Questo elencherà tutti i precedenti HEAD

git reflog

2. Questo ripristinerà HEAD per il commit che hai eliminato.

git reset --hard <your deleted commit>
ex. git reset --hard b4b2c02

1
Non ho mai effettuato il check-in nel ramo localmente quindi il mio HEAD non è mai stato lì, quindi non riesco a trovare l'ID commit con git reflog. C'è qualcos'altro che posso provare?
zyy

1
Come @zyy Il commit è stato cancellato da un altro membro del team in remoto, quindi devo recuperarlo nella mia macchina locale (non ho mai avuto quel commit localmente) e rimandarlo indietro ...
OmGanesh

11

I tuoi rami eliminati non vengono persi, sono stati copiati in origin / contact_page e origin / new_pictures "rami di monitoraggio remoto" dal recupero che hai mostrato (sono stati anche respinti dalla spinta che hai mostrato, ma sono stati inseriti in refs / remotes / origine / invece di refs / heads /). Controlla git log origin/contact_pagee git log origin/new_picturesper vedere se le tue copie locali sono "aggiornate" con quello che pensi dovrebbe essere lì. Se sono stati inseriti nuovi commit su quei rami (da qualche altro repository) tra il recupero e il push che hai mostrato, potresti averli "persi" (ma probabilmente potresti trovarli nell'altro repository che ha spinto di recente quei rami) .

Recupera / Push Conflict

Sembra che tu stia recuperando in una normale 'modalità remota' (i riferimenti remoti / testine / sono memorizzati localmente in refs / remotes / origin /), ma premendo in 'mirror mode' (i riferimenti locali / vengono inseriti nei riferimenti remoti /) . Controlla il tuo .git / config e riconcilia il fileremote.origin.fetchremote.origin.push impostazioni e .

Fai un backup

Prima di provare qualsiasi modifica, crea un semplice archivio tar o zip o l'intero repository locale. In questo modo, se non ti piace quello che succede, puoi riprovare da un repository ripristinato.

Opzione A: riconfigurare come mirror

Se intendi utilizzare il tuo repository remoto come mirror di quello locale, fai questo:

git branch contact_page origin/contact_page &&
git branch new_pictures origin/new_pictures &&
git config remote.origin.fetch '+refs/*:refs/*' &&
git config --unset remote.origin.push &&
git config remote.origin.mirror true

Potresti anche voler cancellare tutti i tuoi ref / telecomandi / origine / ref, poiché non sono utili se stai operando in modalità mirror (i tuoi rami normali prendono il posto dei soliti rami di tracciamento remoto).

Opzione B: riconfigurare come telecomando normale

Ma poiché sembra che tu stia usando questo repository remoto con più repository di "lavoro", probabilmente non vorrai usare la modalità mirror. Potresti provare questo:

git config push.default tracking &&
git config --unset remote.origin.push
git config --unset remote.origin.mirror

Poi, alla fine vuole eliminare i falsi refs / telecomandi / arbitri origine nella repo remoto: git push origin :refs/remotes/origin/contact_page :refs/remotes/origin/new_pictures ….

Prova push

Prova git push --dry-runa vedere cosa git pushfarebbe senza dover apportare modifiche sul repository remoto. Se non ti piace quello che dice che sta per fare, ripristina dal tuo backup (tar / zip) e prova l'altra opzione.


1
Non credo che i rami di monitoraggio remoto siano stati mantenuti, ammesso che siano stati copiati. 'git branch -a' non li mostra e non riesco a trovare alcun file con quei nomi nella directory .git. Infine, i comandi "git log" che hai consigliato restituiscono "fatal: argomento ambiguo 'origin / contact_page': revisione sconosciuta o percorso non nell'albero di lavoro": - \ Grazie comunque.
Craig Walker

1
Bene, quei rami erano lì, il tuo registro push lo mostra. Quando cerchi refs nella .gitdirectory, assicurati di controllare .git/packed_refsoltre a .git/refs/. git show-refscaricherà tutti i tuoi ref locali (imballati o "sciolti"). Dovresti comunque essere in grado di trovare i ref nel repository che li ha originariamente spinti al tuo repository GitHub (su una macchina diversa? Il repository di qualcun altro?). In mancanza di questo, fino a quando non si è fatto un gc o prugna, si dovrebbe essere in grado di l' git fsckuscita di esaminare i commit penzoloni e riattaccare: git branch contact_page-recovered <SHA-1-of-dangling-commit>.
Chris Johnsen

Anche imballato_refs non ce l'aveva. I commit erano decisamente sospesi; nessuna idea di come sia successo. Grazie per il tuo aiuto però!
Craig Walker

8

Se l'eliminazione è abbastanza recente (come un momento Oh-NO!) Dovresti comunque avere un messaggio:

Deleted branch <branch name> (was abcdefghi).

puoi ancora eseguire:

git checkout abcdefghi

git checkout -b <some new branch name or the old one>


8
  1. scopri coimmit id

    git reflog

  2. recuperare il ramo locale che hai cancellato per errore

    git branch need-recover-branch-name commitId

  3. spingere di nuovo need-recover-branch-name se prima hai eliminato anche il ramo remoto

    git push origin need-recover-branch-name


2
Questo ha funzionato per me. Preferisco la risposta accettata perché erano molti meno passaggi. Sono stato in grado di vedere il mio messaggio di commit da git reflog, piuttosto che dover indovinare e git show.
theUtherSide

3

I dati esistono ancora in GitHub, puoi creare un nuovo ramo dai vecchi dati:

git checkout origin/BranchName #get a readonly pointer to the old branch
git checkout –b BranchName #create a new branch from the old
git push origin BranchName #publish the new branch

1

Penso che tu abbia una configurazione non corrispondente per "fetch" e "push", quindi questo ha causato un errore di andata e ritorno predefinito. Fortunatamente hai recuperato i rami che hai successivamente cancellato quindi dovresti essere in grado di ricrearli con un push esplicito.

git push origin origin/contact_page:contact_page origin/new_pictures:new_pictures

Come per il mio commento a @Chris Johnson, sembra che i rami non esistano più (mai?) A livello locale. Quando git push origin origin/contact_page:contact_pageottengo questo: error: src refspec origin/contact_page does not match any
Craig Walker

OK, penso di vedere cosa è successo, (anche se l'errore completo sarebbe utile). push ha aggiornato il ramo cancellato e rimosso il riferimento localmente così come è un riferimento di tracciamento. Cosa git rev-parse refs/remotes/origin/origin/contact_pagedice? A causa della configurazione "mirror" fasulla, il ramo my ora è referenziato qui nel repository locale.
CB Bailey

Ciao Charles; Da quando ho scritto questo ho modificato (e corretto) la mia configurazione in modo da non poter più ottenere l'output (significativo) di rev-parse. Tuttavia, non credo ci fosse una directory "origin" a doppio annidamento nei telecomandi.
Craig Walker

0

Se la tua organizzazione utilizza JIRA o un altro sistema simile collegato a git, puoi trovare i commit elencati nel ticket stesso e fare clic sui collegamenti alle modifiche al codice. Github elimina il ramo ma ha ancora i commit disponibili per la selezione.


-1

Può sembrare troppo cauto, ma spesso comprimo una copia di qualsiasi cosa su cui stavo lavorando prima di apportare modifiche al controllo del codice sorgente. In un progetto Gitlab a cui sto lavorando, di recente ho eliminato per errore un ramo remoto che volevo mantenere dopo aver unito una richiesta di unione. Si scopre che tutto quello che dovevo fare per riaverlo con la cronologia dei commit è stato spingere di nuovo. La richiesta di unione è stata ancora monitorata da Gitlab, quindi mostra ancora l'etichetta blu "unita" a destra del ramo. Ho comunque zippato la mia cartella locale nel caso in cui fosse successo qualcosa di brutto.

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.