Git: Odzyskaj usuniętą (zdalną) gałąź

95

Muszę odzyskać dwie gałęzie Git, które w jakiś sposób usunąłem podczas wypychania.

Te dwie gałęzie zostały utworzone w innym systemie, a następnie przesłane do mojego „współdzielonego” (github) repozytorium.

W moim systemie (najwyraźniej) odzyskałem gałęzie podczas pobierania:

~/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

Zaraz po tym zrobiłem nacisk, aby wysłać moje lokalne zmiany do centralnego repozytorium. Z jakiegoś powodu te gałęzie zostały usunięte zarówno z mojego systemu lokalnego, jak i centralnego repozytorium:

~/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 [email protected]: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

Nie jest strasznie łatwo zdjąć gałęzie z ich maszyny w miejscu urodzenia, więc chciałbym spróbować je odzyskać z mojego lokalnego, jeśli to możliwe.

Wszystkie informacje o „cofnięciu” przez git, które przeszukałem w Google, muszą przy odzyskiwaniu utraconych zatwierdzeń. Nie sądzę, żeby to miało tutaj zastosowanie, ponieważ nie mam identyfikatorów UID dla tych gałęzi.

Chciałbym wiedzieć, jak mogę je odzyskać. Chciałbym również wiedzieć, w jaki sposób zostały one usunięte w pierwszej kolejności i jak mogę tego uniknąć w przyszłości.

EDYCJA: na żądanie, oto moja konfiguracja repozytorium

user.name=Craig Walker
[email protected]
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/*
[email protected]: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
Craig Walker
źródło
Wygląda na to, że masz „nietypową” lub niedopasowaną konfigurację pobierania i wysyłania. Co git config -lpokazuje lokalne repozytorium?
CB Bailey,
Całkiem możliwe; Wysłałem to.
Craig Walker,
2
Twój remote.origin.fetchrefspec nie jest odpowiedni do użytku z remote.origin.mirror = true. Czy chcesz dublować, czy chcesz używać repozytorium GitHub jako normalnego pilota? Moja odpowiedź powinna zawierać polecenia, których potrzebujesz.
Chris Johnsen,
Zgaduję, że w drugim repozytorium dublowanie nie jest już opcją (prawdopodobnie spowodowało to usunięcie w pierwszej kolejności).
Craig Walker,

Odpowiedzi:

103

Nie jestem ekspertem. Ale możesz spróbować

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

znaleźć zatwierdzenie HEAD usuniętej gałęzi i odzyskać je.

iamamac
źródło
Próbowałem wcześniej fsck; czy wiesz, jak się dowiedzieć, który commit jest właściwy? Mam 20 do spróbowania.
Craig Walker
1
Zrobiło to; kiedy miałem komunikaty o zmianach, git branch <uid>odzyskałem je. Dzięki!
Craig Walker,
Dobrze to słyszeć. Upewnij się również, że rozwiązałeś konflikt między swoim remotes.origin.mirrora remotes.origin.fetchustawieniami, w przeciwnym razie ponownie napotkasz problem (lub nieumyślnie przepchniesz zatwierdzenia typu clobber z innych repozytoriów).
Chris Johnsen,
@Craig: Cieszę się, że mogłem być pomocny :)
iamamac
3
Straciłem dziś oddział kandydata do wydania. Nie znałem numeru zatwierdzenia. Odzyskano go za pomocą:git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
spezifanta
23

tylko dwa polecenia ratują mi życie

1. Spowoduje to wyświetlenie wszystkich poprzednich HEADów

git reflog

2. Spowoduje to przywrócenie HEAD do zatwierdzenia, które usunąłeś.

git reset --hard <your deleted commit>
ex. git reset --hard b4b2c02
chinnawatp
źródło
1
Nigdy nie sprawdzałem lokalnie w oddziale, więc mój HEAD nigdy tam nie był, dlatego nie mogę znaleźć identyfikatora zatwierdzenia z git reflog. Czy jest coś jeszcze, co mogę spróbować?
zyy
1
Tak samo jak @zyy, zatwierdzenie zostało usunięte przez innego członka zespołu na zdalnym komputerze, więc muszę go odzyskać na moim lokalnym komputerze (nigdy nie miałem tego zatwierdzenia lokalnie) i
odłożyć
11

Twoje usunięte gałęzie nie zostaną utracone, zostały skopiowane do origin / contact_page i origin / new_pictures „zdalne gałęzie śledzenia” przez pobranie, które pokazałeś (zostały również wypchnięte z powrotem przez pokazany push, ale zostały zepchnięte do refs / remotes / pochodzenie / zamiast referencji / głowy /). Sprawdź git log origin/contact_pagei git log origin/new_pictureszobacz, czy Twoje lokalne kopie są „aktualne” z tym, co Twoim zdaniem powinno tam być. Jeśli jakieś nowe zatwierdzenia zostałyby wypchnięte do tych gałęzi (z innego repozytorium) między pobraniem a wypychaniem, które pokazałeś, być może je „zgubiłeś” (ale prawdopodobnie mógłbyś je znaleźć w innym repozytorium, które ostatnio wypchnęło te gałęzie) .

Konflikt pobierania / wysyłania

Wygląda na to, że pobierasz w normalnym, `` trybie zdalnym '' (zdalne referencje / głowice / są przechowywane lokalnie w referencjach / zdalnych / pochodzenia /), ale wciskasz w `` trybie lustrzanym '' (lokalne referencje / są wypychane do zdalnych referencji /) . Sprawdź swój plik .git / config i uzgodnij ustawienia remote.origin.fetchi remote.origin.push.

Utwórz kopię zapasową

Przed wypróbowaniem jakichkolwiek zmian utwórz proste archiwum tar lub zip lub całe lokalne repozytorium. W ten sposób, jeśli nie podoba ci się to, co się dzieje, możesz spróbować ponownie z przywróconego repozytorium.

Opcja A: Zmień konfigurację jako lustro

Jeśli zamierzasz używać zdalnego repozytorium jako lustra lokalnego, zrób to:

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

Możesz też w końcu zechcieć usunąć wszystkie swoje referencje / zdalne / pochodzenie / referencje, ponieważ nie są one przydatne, jeśli pracujesz w trybie lustrzanym (twoje normalne gałęzie zajmują miejsce zwykłych gałęzi zdalnego śledzenia).

Opcja B: Skonfiguruj ponownie jako zwykłego pilota

Ale ponieważ wydaje się, że używasz tego zdalnego repozytorium z wieloma repozytoriami „roboczymi”, prawdopodobnie nie chcesz używać trybu lustrzanego. Możesz spróbować tego:

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

Następnie w końcu będziesz chciał usunąć fałszywe refs / remotes / origin refs w swoim zdalnym repozytorium: git push origin :refs/remotes/origin/contact_page :refs/remotes/origin/new_pictures … .

Test Push

Spróbuj git push --dry-runzobaczyć, co git pushby zrobił, nie zmuszając go do wprowadzania jakichkolwiek zmian w zdalnym repozytorium. Jeśli nie podoba ci się to, co mówi, że zrobi, odzyskaj z kopii zapasowej (tar / zip) i wypróbuj inną opcję.

Chris Johnsen
źródło
1
Nie sądzę, by zachowano gałęzie zdalnego śledzenia, jeśli w ogóle zostały skopiowane. „git branch -a” ich nie pokazuje, a także nie mogę znaleźć żadnych plików o tych nazwach w katalogu .git. Na koniec polecenia „git log”, które poleciłeś, zwracają „fatal: niejednoznaczny argument 'origin / contact_page': nieznana wersja lub ścieżka poza drzewem roboczym”: - \ Dzięki.
Craig Walker,
1
Cóż, te gałęzie tam były, twój dziennik wypychania to pokazuje. Szukając referencji w .gitreż, koniecznie sprawdź .git/packed_refsoprócz .git/refs/. git show-refzrzuci wszystkie lokalne referencje (spakowane lub „luźne”). Nadal powinieneś być w stanie znaleźć referencje w repozytorium, które pierwotnie wypchnęło je do repozytorium GitHub (na innym komputerze? Czyimś repozytorium?). W przypadku jego braku, o ile jeszcze tego nie zrobiłeś GC lub śliwki, powinieneś być w stanie do git fsckwyjścia do zbadania zwisające zobowiązuje i załóż je: git branch contact_page-recovered <SHA-1-of-dangling-commit>.
Chris Johnsen,
Packed_refs też go nie ma. Commity zdecydowanie zwisały; nie mam pojęcia, jak to się stało. Ale dzięki za pomoc!
Craig Walker,
8

Jeśli usunięcie nastąpiło wystarczająco niedawno (jak w momencie O-NIE!), Nadal powinieneś otrzymać wiadomość:

Deleted branch <branch name> (was abcdefghi).

nadal możesz biegać:

git checkout abcdefghi

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

Timmy
źródło
8
  1. dowiedzieć się coimmit id

    git reflog

  2. odzyskać lokalny oddział, który został przez pomyłkę usunięty

    git branch need-recover-branch-name commitId

  3. push need-recovery-branch-name ponownie, jeśli wcześniej usunąłeś również zdalną gałąź

    git push origin need-recover-branch-name

JackChouMine
źródło
2
To zadziałało dla mnie. Wolę od zaakceptowanej odpowiedzi, ponieważ było to znacznie mniej kroków. Byłem w stanie zobaczyć moją wiadomość o zatwierdzeniu git reflog, zamiast zgadywać i git show.
theUtherSide
3

Dane nadal istnieją na githubie, możesz utworzyć nową gałąź ze starych danych:

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
jhilden
źródło
1

Myślę, że masz niedopasowaną konfigurację dla „pobierania” i „wypychania”, co spowodowało, że domyślne pobieranie / wypychanie nie działało prawidłowo. Na szczęście pobrałeś gałęzie, które później usunąłeś, więc powinieneś być w stanie je odtworzyć za pomocą wyraźnego push.

git push origin origin/contact_page:contact_page origin/new_pictures:new_pictures
CB Bailey
źródło
Podobnie jak w przypadku mojego komentarza do @Chris Johnson, wygląda na to, że oddziały już (nigdy?) Nie istnieją lokalnie. Kiedy git push origin origin/contact_page:contact_pagedostaję to: error: src refspec origin/contact_page does not match any
Craig Walker
OK, chyba widzę co się stało (chociaż pełny błąd byłby pomocny). push zaktualizował usuniętą gałąź i usunął lokalnie referencję, jak również jest to referencja śledząca. Co git rev-parse refs/remotes/origin/origin/contact_pagemówi? Z powodu fałszywej konfiguracji 'mirrora', gałąź może być teraz przywoływana w lokalnym repozytorium.
CB Bailey,
Cześć Charles; Odkąd to napisałem, zmieniłem (i naprawiłem) moją konfigurację, więc nie mogę już uzyskać (znaczącego) wyniku analizy obrotów. Jednak nie sądzę, aby w pilotach istniał podwójnie zagnieżdżony katalog „pochodzenia”.
Craig Walker,
0

Jeśli Twoja organizacja korzysta z JIRA lub innego podobnego systemu, który jest powiązany z git, możesz znaleźć zatwierdzenia wymienione na samym zgłoszeniu i kliknąć łącza do zmian kodu. Github usuwa gałąź, ale nadal ma dostępne zatwierdzenia do wyboru.

Roralee
źródło
-1

Może się to wydawać zbyt ostrożne, ale często spakuję kopię tego, nad czym pracowałem, zanim wprowadzę zmiany w kontroli źródła. W projekcie Gitlab, nad którym pracuję, niedawno przez pomyłkę usunąłem zdalną gałąź, którą chciałem zachować po scaleniu żądania scalenia. Okazuje się, że wszystko, co musiałem zrobić, aby odzyskać to z historią zmian, to ponowne wciśnięcie. Żądanie scalenia było nadal śledzone przez Gitlab, więc nadal pokazuje niebieską etykietę „scalone” po prawej stronie gałęzi. Nadal spakowałem folder lokalny na wypadek, gdyby stało się coś złego.

Artorias2718
źródło