Jak mogę odzyskać od błędnego wzorca pochodzenia git push -f?

93

Po prostu popełniłem niewłaściwe źródło w moim projekcie za pomocą --forceopcji.

Czy można cofnąć? Rozumiem, że wszystkie poprzednie gałęzie zostały nadpisane za pomocą -fopcji, więc mogłem schrzanić poprzednie wersje.

David van Dugteren
źródło
możliwy duplikat Is anyway to undo git push -f?
cmbuckley

Odpowiedzi:

55

Git generalnie niczego nie odrzuca, ale odzyskanie z tego może nadal być trudne.

Jeśli masz prawidłowe źródło, możesz po prostu wrzucić je do pilota za pomocą --forceopcji. Git nie usunie żadnych gałęzi, chyba że o tym poprosisz. Jeśli rzeczywiście zgubiłeś zatwierdzenia, zapoznaj się z tym przydatnym przewodnikiem po odzyskiwaniu zatwierdzeń . Jeśli znasz SHA-1 żądanych zatwierdzeń, prawdopodobnie wszystko jest w porządku.

Najlepsza rzecz do zrobienia: wykonaj kopię zapasową wszystkiego i zobacz, co jest nadal w lokalnym repozytorium. Jeśli to możliwe, zrób to samo na pilocie. Użyj, git fsckaby sprawdzić, czy możesz odzyskać rzeczy, a przede wszystkim NIE biegaćgit gc .

Przede wszystkim nigdy nie używaj tej --forceopcji, chyba że naprawdę masz to na myśli.

Cameron Skinner
źródło
64
Najprawdopodobniej wystarczy spojrzeć na reflogs, aby określić, gdzie pierwotnie znajdowały się zdalne gałęzie. Na przykład git reflog show remotes/origin/master. Powinieneś być w stanie zobaczyć tam swój nacisk; zatwierdzenie w poprzedniej linii jest tam, gdzie było, zanim to zepsułeś. Następnie możesz po prostu wrzucić tę wersję (z --force) do początku i wrócić tam, gdzie byłeś!
Cascabel
@David: Och. Nie wspomniałeś w swoim pytaniu, że nie masz repozytorium. (Jest to oczywiście coś, czego nigdy nie chcesz robić). Jeśli jednak masz dostęp do systemu plików tam, gdzie zostałeś przeniesiony, nadal możesz to wszystko zrobić.
Cascabel
1
@David: Yikes. Zawsze dobrze jest mieć aktualny katalog jako część zachęty, aby uniknąć tego rodzaju rzeczy.
Cascabel
1
@Jefromi Myślę, że to, co powiedziałeś, jest właściwą odpowiedzią: Nawet ze starą wersją (nie git fetchedytowaną przez długi czas) możesz wyświetlić reflog strony GitHub i odzyskać!
nh2
1
Gdzie jest ta odpowiedź od @Jefromi? Nie widzę tego użytkownika wymienionego na tej stronie poza tym wątkiem komentarzy.
Don McCurdy
47

Jeśli znasz skrót zatwierdzenia, jest to łatwe, po prostu ponownie utwórz gałąź.

5794458...b459f069 master -> master (forced update)

Usuń zdalną gałąź:

git push origin :master

następnie odtwórz swoją gałąź za pomocą następujących poleceń:

git checkout 5794458
git branch master
git push origin master
user1094125
źródło
28

Rozwiązanie zostało już tutaj wspomniane

# work on local master
git checkout master

# reset to the previous state of origin/master, as recorded by reflog
git reset --hard origin/master@{1}

# at this point verify that this is indeed the desired commit.
# (if necessary, use git reflog to find the right one, and
# git reset --hard to that one)

# finally, push the master branch (and only the master branch) to the server
git push -f origin master
Abdelhafid
źródło
Dziękuję, to zadziałało dla mnie. Nie miałem dostępu do usuwania wzorca, więc zatwierdzony komentarz nie powiódł się.
Andi
Tak, i git reflog show remotes/origin/masterjeśli git reflog jest konieczny (jak wspomniano powyżej @ Cascabel)
Josiah Yoder
2
To jest prawidłowa odpowiedź, dzięki za link do właściwej.
Noitidart
6

Jeśli nie znajdujesz się w tym lokalnym repozytorium, z którego pochodzi wymuszony push, na poziomie początkowym / głównym nie ma możliwości odzyskania. Ale jeśli masz szczęście korzystać z GitHub lub GitHub for Enterprise , możesz zajrzeć do REST API i odzyskać utracone zatwierdzenie jako łatkę, na przykład:

  1. Wyświetl listę zdarzeń i znajdź długi format sha1 commit

https://api.github.com/repos/apache/logging-log4j2/events

  1. Pobierz utracone zatwierdzenie i pobierz powiązaną poprawkę ze ścieżki json .files [] / patch

https://api.github.com/repos/apache/logging-log4j2/commits/889232e28f3863d2a17392c06c1dd8cac68485de

  1. Zastosuj lokalnie i naciśnij ponownie

git zastosuj patch.patch && git commit -m "restored commit" && git push origin master

Pierrick HYMBERT
źródło
4

Innym sposobem na odzyskanie utraconego zatwierdzenia lub nawet dowiedzieć się, które zatwierdzenia zostały utracone, jeśli poprzednie wypychanie nie pochodziło z lokalnego repozytorium, polega na spojrzeniu na maszynę CI.

Jeśli masz zadanie, które testuje gałąź główną po każdym zatwierdzeniu (lub serii kolejnych zatwierdzeń), które powinieneś wykonać, możesz zobaczyć, co testowało ostatnio. To jest zobowiązanie, które musisz przywrócić.

Maszyna CI może nawet zachować lokalny klon repozytorium, z którego można będzie wykonać to odzyskiwanie.

Źródło: prawdopodobnie ciągła dostawa: niezawodne wydania oprogramowania dzięki automatyzacji kompilacji, testowania i wdrażania (seria Addison-Wesley Signature (Fowler))

user7610
źródło
3

Tak, możesz odzyskać zatwierdzenia po git push -f your_branch

Tekst z dokumentu :

Wyczyść wpisy starsze niż określony czas. Jeśli ta opcja nie jest określona, ​​czas wygaśnięcia jest pobierany z ustawienia konfiguracyjnego gc.reflogExpire, które z kolei wynosi domyślnie 90 dni. --expire = wszystkie wpisy dotyczące suszonych śliwek niezależnie od ich wieku; --expire = nigdy nie wyłącza przycinania osiągalnych wpisów (ale zobacz --expire-unreachable).

Możesz więc:

1- git reflog

wprowadź opis obrazu tutaj

2- wybierasz Head_Number, z którym chcesz odzyskać git reset –hard HEAD@{HEAD-NUMBER}

wprowadź opis obrazu tutaj

3- Możesz zobaczyć wszystkie zatwierdzenia na tej głowie według git cherry -v branch_name

4- w końcu powinieneś wymusić pchnięcie git push -f branch_name

LUB

1- Uzyskaj liczbę SHA z klienta GIT (interfejsu)

git reset --hard commit_SHA

2- siła pchająca

git push -f your_branch

Mam nadzieję że to pomoże

Jakub
źródło
2

Zrobiłem to samo, cofając ostatnie naciśnięcie tylko jednego pliku. Skończyło się na przywróceniu pierwotnego stanu repozytorium. Używałem poleceń git od Linusa, ponieważ miałem lokalną kopię w systemie Linux. Na szczęście ta kopia była nadal nienaruszona.

Wszystko, co zrobiłem (po gorączkowym wykonaniu kilku kolejnych kopii lokalnego repozytorium):

git add .
git status

(powiedział, że origin / master wyprzedził o 68 commits, dobrze ... to były wszystkie zatwierdzenia, które usunąłem)

git remote set-url origin <GIT_SSH_URL>
git push

I wszystko zostało przywrócone tak, jak było, zanim zrobiłem silny nacisk. Najważniejszą rzeczą do zapamiętania jest to, aby nigdy nie wykonywać transakcji git. po tym, jak mocno pchnąłeś. Ale najlepszą praktyką jest wyłączenie opcji wypychania. Nigdy więcej go nie używam. Nauczyłem się mojej lekcji !!

Pran
źródło
1

Dla osób w naprawdę złych sytuacjach, takich jak ja (na przykład, jeśli otrzymujesz bad objectbłędy podczas uruchamiania git reset --hard):

Napisałem skrypt o nazwie treesaver, który w ostateczności pobiera wszystkie twoje pliki z GitHub API. Oto jak z niego korzystać:

  1. Sklonuj treesaverskrypt i cddo niego.
  2. Znajdź SHAciąg drzewa, które chcesz przywrócić, uzyskując dostęp https://api.github.com/repos/<your_username_or_org>/<repo>/events.
  3. W payloadwłaściwości odpowiadającej Twojemu zdarzeniu push znajdź to commit, do którego chcesz powrócić, i kliknij je url.
  4. Pod commit.treeskopiuj treeplik url.
  5. Biegnij python3 main.py <tree_url> <path_to_save_to>.

Na przykład w moim przypadku uruchomiłbym:

python3 main.py https://api.github.com/repos/anthonykrivonos/my-repo/git/trees/1234567 .

Oczywiście PR mile widziane.

Anthony Krivonos
źródło
0

Tutaj możesz przeczytać decyzje https://evilmartians.com/chronicles/git-push---force-and-how-to-deal-with-it

Drugi mi pomógł. Zrobiłem źle te polecenia

1) (some-branch) git pull -> correct command was git pull origin some-branch

2) (some-branch) git push -f origin some-branch

Po tych komendach straciłem trzy commity. Aby je odzyskać, spojrzałem na terminal, w którym źle wykonałem `` git pull '' i zobaczyłem, jak wygląda

60223bf ... 0b258eb jakaś gałąź -> pochodzenie / jakaś gałąź

Drugi skrót 0b258eb był dokładnie tym, czego potrzebowałem. Więc wziąłem ten hash i wydałem polecenie

git push --force origin 0b258eb:some-branch
Andrey
źródło