Jak „git pull” zjadł moją pracę domową?

53

Czuję się jak dziecko w biurze dyrektora wyjaśniające, że pies zjadł moją pracę domową w noc przed jej terminem, ale gapię się na jakiś szalony błąd utraty danych w twarz i nie mogę zrozumieć, jak to się stało. Chciałbym wiedzieć, jak git mógłby zjeść całe moje repozytorium! Wiele razy przerzucałem gitarzystę i nigdy nie mrugał. Użyłem go, aby podzielić repozytorium 20 Gig Subversion na 27 repozytoriów git i rozgałęzić foo z nich, aby rozwiązać bałagan i nigdy nie straciłem bajta na mnie. Reflog jest zawsze dostępny. Tym razem dywan zniknął!

Z mojej perspektywy wszystko, co zrobiłem, to uruchomić git pulli zniszczyć moje całe lokalne repozytorium. Nie chodzi mi o to, że „popsuła sprawdzoną wersję”, „gałąź, w której byłam”, czy coś w tym rodzaju. Mam na myśli, że cała rzecz zniknęła .

Oto zrzut ekranu mojego terminalu podczas incydentu:

zrzut ekranu z incydentu

Pozwól mi przejść przez to. Mój wiersz polecenia zawiera dane o bieżącym repozytorium git (używając implementacji vcs_info prezto), dzięki czemu możesz zobaczyć, kiedy repozytorium git zniknęło. Pierwsze polecenie jest wystarczająco normalne:

  » caleb » jaguar » ~/p/w/incil.info » ◼  zend ★ »
❯❯❯ git co master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

Tam widać, że byłem w gałęzi „zend” i sprawdziłem master. Na razie w porządku. Zobaczysz w pytaniu przed moim następnym poleceniem, że pomyślnie przełącza gałęzie:

  » caleb » jaguar » ~/p/w/incil.info » ◼  master ★ »
❯❯❯ git pull
remote: Counting objects: 37, done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 37 (delta 25), reused 0 (delta 0)
Unpacking objects: 100% (37/37), done.
From gitlab.alerque.com:ipk/incil.info
 + 7412a21...eca4d26 master     -> origin/master  (forced update)
   f03fa5d..c8ea00b  devel      -> origin/devel
 + 2af282c...009b8ec verse-spinner -> origin/verse-spinner  (forced update)
First, rewinding head to replay your work on top of it...
>>> elapsed time 11s

I po prostu zniknęło. Znacznik czasu, który upłynął, wyświetla się przed następnym monitem, jeśli upłynęło więcej niż 10 sekund. Git nie dał żadnego wyjścia poza powiadomieniem, że przewijało się, by powtórzyć. Nic nie wskazuje na to, że się skończyło.

Następny monit nie zawiera danych o tym, w której gałęzi jesteśmy ani o stanie git.

Nie zauważając, że się nie powiodło, nieświadomie próbowałem uruchomić inną komendę git, aby powiedzieć, że nie jestem w repozytorium git. Uwaga: PWD nie zmieniło się:

  » caleb » jaguar » ~/p/w/incil.info »
❯❯❯ git fetch --all
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

Po tym rozejrzenie się wykazało, że jestem w całkowicie pustym katalogu. Nic. Brak katalogu „.git”, nic. Pusty.

Mój lokalny git jest w wersji 2.0.2. Oto kilka ciekawostek z mojej konfiguracji git, które mogą być istotne dla zrozumienia, co się stało:

[branch]
        autosetuprebase = always
        rebase = preserve
[pull]
        rebase = true
[rebase]
        autosquash = true
        autostash = true
[alias]
        co = checkout

Na przykład git pullustawiłem, aby zawsze wykonywać rebase zamiast scalania, aby część powyższego wyniku była normalna.

Mogę odzyskać dane. Nie sądzę, żeby istniały jakieś przedmioty git inne niż nieistotne skrytki, które nie zostały przekazane innym repozytoriom, ale chciałbym wiedzieć, co się stało .

Sprawdziłem:

  • Wiadomości w dmesg lub dzienniku systemowym. Nic, nawet zdalnie istotne.
  • Nic nie wskazuje na awarię dysku lub systemu plików (wszystkie LVM + LUKS + EXT4 wyglądają normalnie). Nic nie znaleziono w Lost +.
  • Nie prowadziłem nic innego. W historii nie ma niczego, czego nie pokazuję powyżej, i w tym czasie nie były używane żadne inne terminale. Wokół nie ma żadnych rmpoleceń, które mogłyby zostać wykonane w niewłaściwym CWD itp.
  • Grzebanie w innym repozytorium git w innym katalogu nie wykazuje widocznych nieprawidłowości w wykonywaniu git pulls.

Czego jeszcze powinienem tu szukać?

Caleb
źródło
4
@Patrick Jak już wyjaśniłem w pytaniu, .gitnie istnieje. Nic nie robi - w katalogu głównym git nic nie ma.
Caleb
2
@Alexander Operacja ściągania jest normalna (inna niż regease, a nie scalanie). Zawiadomienie o wymuszonej aktualizacji wskazuje, że repo, z którego ściągam, miało siłę push, która zresetowała go z innej pozycji niż lokalna repo ostatnio widziała. Jest to normalne, ponieważ synchronizuję aktywnie opracowywany i często zmieniany materiał między moimi komputerami, a nie publiczną gałęzią, którą zobaczą inni programiści.
Caleb
3
@ Skaluj polecenie powłoki zawiera wskazanie gałęzi git, co oznacza, że ​​utworzenie PS1 obejmuje polecenia git niewidoczne w twoim dzienniku. Mogą zasadniczo zmieniać obraz i mogą być źródłem problemu. Powinieneś zaktualizować pytanie dokładnie opisujące, jak tworzony jest monit powłoki, jakie polecenia są uruchamiane, aby uzyskać bieżącą gałąź i ponownie rozważyć, w jaki sposób mogą zepsuć twoje repo.
Netch
2
@Caleb Naprawdę powinieneś zapytać na liście mailingowej git development; Możesz napisać to jako zgłoszenie błędu lub po prostu zapytać nieoficjalnie - i tak jest tak samo. Jest kilku programistów, którzy znają git imponująco - prawdopodobnie intuicyjnie potrafią powiedzieć, co mogło się stać. (Jeśli nie, będą po prostu cicho śledzić dyskusję.) I wiedzą, czy to się wcześniej zdarzyło. (Zgłoszenie, że istnieje „oficjalny” sposób zgłaszania błędów dotyczących git)
Volker Siegel,
7
@Wildcard Właściwie chciałem udzielić odpowiedzi na to pytanie, ponieważ właściwie odkryłem, co się stało. System niedawno przeszedł ze snu, a sieć nie działała przez wiele dni, zanim poszła spać. Gdzieś w tym procesie zostawiłem uruchomiony proces Pacmana, który próbował uaktualnić coś w systemie. Krótko mówiąc, okazuje się, że glibc został zaktualizowany, a binarny git został nadpisany. Ze względu na sposób, w jaki się rozwidlało, jedno wystąpienie okazało się inne niż drugie i zjedli sobie obiad. Katalog był naprawdę pusty (nie tylko aparat
Caleb

Odpowiedzi:

6

Tak, gitzjadłem moją pracę domową. Wszystko.

Zrobiłem ddobraz tego dysku po incydencie i pomieszałem go później. Rekonstruując serię zdarzeń z dzienników systemowych, dedukuję, że to, co się stało, było mniej więcej tak:

  1. Polecenie aktualizacji systemu ( pacman -Syu) zostało wydane na kilka dni przed tym zdarzeniem.
  2. Przedłużone awarie sieci spowodowały, że próbowano pobrać pakiety. Sfrustrowany brakiem internetu położyłem system na sen i poszedłem spać.
  3. Kilka dni później system się obudził i zaczął ponownie znajdować i pobierać pakiety.
  4. Pobieranie pakietu zakończyło się tuż przed tym, jak bałam się tego repozytorium.
  5. System glibc montaż został zaktualizowany po git checkouti przed git pull.
  6. Plik gitbinarny został wymieniony po git pulluruchomieniu i przed zakończeniem.
  7. A dnia siódmego gitodpoczął od wszystkich wysiłków. I usunął świat, więc wszyscy inni też musieli odpocząć.

Nie wiem dokładnie, jaki był warunek wyścigu, który to spowodował, ale zamiana plików binarnych w trakcie operacji z pewnością nie jest ani przyjemna, ani możliwa do przetestowania / powtarzalności. Zwykle kopia działającego pliku binarnego jest przechowywana w pamięci, ale gitjest dziwna i coś w tym, jak odradza swoje wersje, jestem pewien, że doprowadziłem do tego bałaganu. Oczywiście powinno raczej umrzeć, niż wszystko zniszczyć, ale tak właśnie się stało.

Caleb
źródło
1
git mógł się nie powieść, ponieważ git tworzy różne polecenia zamiast pojedynczego pliku binarnego. Prosty git pull wykonuje git-fetch, git-rebaseczy git-mergeigit gc
Ferrybig
2

Możliwe, że nie uda się zdefiniować ścieżki pliku do usunięcia.

Twoja sprawa przypomniała mi piękny dzień, kiedy moja domowa remove(path)metoda próbowała usunąć folder główny, ponieważ podanym parametrem był pusty ciąg, który system operacyjny poprawił (!) Jako folder główny.

To może być podobny błąd git. Tak, że:

  1. Polecenie Rebase chciało usunąć plik taki jak remove(project_folder + file_path)(pseudo kod)
  2. Jakoś wtedy file_pathbył pusty.
  3. Polecenie oceniane jako coś w rodzaju remove(project_folder)
Maliaya
źródło
1

Przy odrobinie szczęścia możesz to naprawić za pomocą następującego polecenia:

git reset --hard ORIG_HEAD  

Gdy rozpoczną się potencjalne niebezpieczne zmiany, git ukrywa twój obecny stan w ORIG_HEAD. Za jego pomocą możesz cofnąć scalenie lub zmianę bazy.

Podręcznik Git: Cofanie scalenia

Płyn do płukania jamy ustnej
źródło
4
Nie sądzę, żebyś przeczytał całe pytanie. Tego rodzaju poprawka jest całkowicie wykluczona, ponieważ nie ma metadanych git . Wykonanie takiego resetu wymaga istniejącego katalogu .git i niektórych obiektów w nim, z których można pracować. Nie mam nic. To nie tylko popsuty katalog roboczy, nie jest już żadnym repozytorium.
Caleb
Ach, przepraszam. To jest bardzo nietypowe. Jeśli git repo zniknie, przypuszczam, że nie będzie sposobu na odzyskanie, chyba że będziesz śledzić pliki w systemie Linux i mieć kopie zapasowe plików fs. Usunę moją odpowiedź, ponieważ jest ona nieistotna.
Routhinator
Tak, wiem, że to niezwykły problem (i mam kopie zapasowe). Moje pytanie brzmi: jak poszło nie tak ... gdzie szukać błędu w git, moim sterowniku systemu plików lub czymkolwiek innym, co mogłoby się zdarzyć, że zjadłem katalog w środku takiej operacji.
Caleb
Jestem też bardzo ciekawa. Chciałbym, żeby coś takiego przydarzyło się moim repozytoriom.
Routhinator,
-1

Wygląda git push --forcena to, że ktoś uruchomił to repozytorium, a ty wprowadziłeś zmiany. Spróbuj sklonować repo na świeżo, co powinno przywrócić Cię do czystego stanu pracy.

conorsch
źródło
1
Wymuszone pchnięcie zmieniło ostatnią garść zobowiązań. To nie to, co wyciągnąłem (katalog roboczy nie jest już katalogiem roboczym!), A nawet jeśli byłoby to klonowanie, nie miałoby to sensu.
Caleb
4
Nie sądzę, że można usunąć czyjś .gitkatalog za pomocą wymuszonego pchnięcia
Grzegorz