Cofnąć scalenie przez pull request?

159

Ktoś zaakceptował żądanie ściągnięcia, którego nie powinien. Mamy teraz dołączoną masę uszkodzonego kodu. Jak cofnąć żądanie ściągnięcia? Chciałem tylko cofnąć zmiany w zatwierdzeniu tuż przed scaleniem, ale zauważyłem, że scalił się w kilka zatwierdzeń. Więc teraz są wszystkie te zobowiązania tej osoby z dni przed połączeniem. Jak to cofnąć?

Będzie
źródło
7
Pomimo porady dotyczącej zaakceptowanej odpowiedzi PROSZĘ nie wciskać na siłę do repozytorium, jeśli repozytorium jest udostępniane komukolwiek innemu. Ryzykujesz zrujnowaniem pracy wykonanej przez innych, a GitHub może nadal wyświetlać to żądanie ściągnięcia jako scalone. Inna odpowiedź na to pytanie wyjaśnia bezpieczniejszy sposób cofnięcia żądania ściągnięcia.
alxndr
2
Uwaga: przynajmniej teraz (czerwiec 2014 r.) GitHub proponuje przycisk „Przywróć” w interfejsie web GUI Pull Request. Zobacz moją odpowiedź poniżej
VonC
1
Problem z przyciskiem przywróć polega na tym, że tworzy on nowe zatwierdzenie jako odwrotność żądania ściągnięcia, co oznacza, że ​​jeśli chcesz ostatecznie scalić te zmiany, użycie przycisku „Przywróć” może to znacznie utrudnić.
FluffySamurai

Odpowiedzi:

159

Jest lepsza odpowiedź na ten problem, chociaż mógłbym po prostu rozłożyć to krok po kroku.

Będziesz musiał pobrać i sprawdzić najnowsze zmiany, takie jak na przykład:

git fetch upstream
git checkout upstream/master -b revert/john/foo_and_bar

Patrząc na dziennik zatwierdzeń, powinieneś znaleźć coś podobnego do tego:

commit b76a5f1f5d3b323679e466a1a1d5f93c8828b269
Merge: 9271e6e a507888
Author: Tim Tom <[email protected]>
Date:   Mon Apr 29 06:12:38 2013 -0700

    Merge pull request #123 from john/foo_and_bar

    Add foo and bar

commit a507888e9fcc9e08b658c0b25414d1aeb1eef45e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 12:13:29 2013 +0000

    Add bar

commit 470ee0f407198057d5cb1d6427bb8371eab6157e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 10:29:10 2013 +0000

    Add foo

Teraz chcesz cofnąć całe żądanie ściągnięcia z możliwością późniejszego cofnięcia. Aby to zrobić, będziesz musiał wziąć identyfikator zatwierdzenia scalenia .

W powyższym przykładzie zatwierdzenie scalające znajduje się na górze, gdzie jest napisane „Scalone żądanie ściągnięcia nr 123 ...” .

Zrób to, aby cofnąć obie zmiany ( „Dodaj pasek” i „Dodaj foo” ), a skończysz w jednym zatwierdzeniu, przywracając całe żądanie ściągnięcia, które możesz później cofnąć i zachować czystą historię zmian:

git revert -m 1 b76a5f1f5d3b323679e466a1a1d5f93c8828b269
programista błędów
źródło
6
To powinna być prawidłowa odpowiedź. Na stronie podręcznika git-revert znajduje się odniesienie do dalszych szczegółów z listy dyskusyjnej git tutaj kernel.org/pub/software/scm/git/docs/howto/ ...
Justin Hamade
2
Dlaczego git checkout upstream/master -b revert/john/foo_and_bar? co to dokładnie robi?
Magne
4
@Magne - tworzysz nową gałąź, aby wykonać przywracanie, w którym możesz następnie wybrać, gdzie chcesz scalić powrót. Po prostu daje większą kontrolę nad tym, co zrobić z gałęzią. W moim przypadku przesłałem nowe żądanie ściągnięcia z tej "naprawionej" gałęzi, zawierające powrót do naszej gałęzi deweloperskiej, co oznacza, że ​​moje nowe żądanie ściągnięcia może również zostać cofnięte w razie potrzeby. Zrobiliśmy to dla wydania, w którym zdecydowaliśmy się wyciągnąć pierwszą wersję roboczą funkcji, której harmonogram został zmieniony. Bez złego kodu, po prostu nie wchodzę w tej wersji.
Daniel Nalbach
3
Nauczyłem się trudnej lekcji na ten temat. Wypchnęliśmy funkcję do naszej gałęzi deweloperskiej, ale zdaliśmy sobie sprawę, że wystąpiły problemy z danymi i przywróciliśmy ją bezpośrednio podczas tworzenia. Później, gdy rzeczy zostały naprawione, chcieliśmy dodać nowsze funkcje programistyczne z powrotem do tej gałęzi, aby przetestować ich zgodność z tą funkcją przed wypchnięciem, więc połączyłem programowanie z powrotem do gałęzi funkcji. Dotyczyło to również zatwierdzenia rewersji, które anulowało każdą zmianę wprowadzoną w gałęzi funkcji. > <
Greg,
86

Spójrz na swój wykres zatwierdzenia (z gitk lub podobnym programem). Zobaczysz zatwierdzenia z żądania ściągnięcia i zobaczysz własne zatwierdzenia i zatwierdzenie scalające (jeśli nie było to szybkie scalanie do przodu). Musisz tylko znaleźć ostatnie własne zatwierdzenia przed scaleniem i zresetować gałąź do tego zatwierdzenia.

(Jeśli masz reflog gałęzi, znalezienie zatwierdzenia przed scaleniem powinno być jeszcze łatwiejsze).


(Edytuj po więcej informacji w komentarzach :)

OK, spójrzmy na wykres:

zrzut ekranu 1

Zakładam, że ostatnim (najbardziej po prawej) zatwierdzeniem było twoje złe połączenie przez pull request , które połączyło niebieską linię widoczną tutaj. Twoim ostatnim dobrym zatwierdzeniem byłoby to, co wcześniej na czarnej linii, tutaj zaznaczone na czerwono:

wprowadź opis obrazu tutaj

Zresetuj do tego zatwierdzenia i powinno być dobrze.

Oznacza to, że w swojej lokalnej kopii roboczej zrób to (po upewnieniu się, że nie masz więcej niezaangażowanych rzeczy, na przykład przez git stash):

git checkout master
git reset --hard 7a62674ba3df0853c63539175197a16122a739ef
gitk 

Teraz potwierdź, że naprawdę jesteś na zatwierdzeniu, które tam zaznaczyłem, a nie zobaczysz żadnego z wyciągniętych rzeczy w jego przodkach.

git push -f origin master

(jeśli nazwany jest twój pilot github origin- w przeciwnym razie zmień nazwę).

Teraz też wszystko powinno wyglądać dobrze na githubie. Zatwierdzenia nadal będą w twoim repozytorium, ale nie będą dostępne dla żadnej gałęzi, więc nie powinny tam wyrządzić żadnej szkody. (I oczywiście nadal będą w repozytorium RogerPaladin).

(Może istnieć specyficzny dla serwisu Github sposób na zrobienie tego samego, ale nie jestem zbyt zaznajomiony z Githubem i jego systemem zarządzania żądaniami ściągnięcia).

Zauważ, że jeśli ktoś inny mógł już wyciągnąć twojego mastera z niewłaściwym zatwierdzeniem, wtedy ma ten sam problem, co obecnie i nie może tak naprawdę wnieść wkładu. przed zresetowaniem do nowej wersji głównej.

Jeśli jest prawdopodobne, że tak się stało, lub po prostu chcesz uniknąć problemów, użyj git revertpolecenia zamiast git reset, aby cofnąć zmiany nowym zatwierdzeniem, zamiast przywracać starsze. (Niektórzy uważają, że nigdy nie powinieneś resetować z opublikowanymi gałęziami.) Zobacz inne odpowiedzi na to pytanie, jak to zrobić.

Na przyszłość:

Jeśli chcesz tylko niektórych zatwierdzeń gałęzi RogerPaladin, rozważ użycie cherry-pickzamiast merge. Lub skontaktuj się z RogerPaladin, aby przenieść je do oddzielnej gałęzi i wysłać nowe żądanie ściągnięcia.

Paŭlo Ebermann
źródło
Ale mamy mnóstwo zatwierdzeń między fuzją a jego pierwszym zatwierdzeniem. Tak jak mamy zatwierdzenie scalające, nasze własne zatwierdzenia, a następnie kolejne zatwierdzenie przez niego. Wygląda na to, że wtopił się w jego naprawdę stare commity.
Będzie
Tak, połączy się ze wszystkim, co jest przodkiem połączonego zatwierdzenia (a nie jest już przodkiem twojego zatwierdzenia). Nie powinno to przeszkadzać w zresetowaniu - zatwierdzenia nie zostaną ponownie uporządkowane samodzielnie, jeśli później nie dokonałeś ponownej bazy.
Paŭlo Ebermann
1
Tak, teraz wygląda dobrze (poza dziwnym połączeniem w siebie - ale może to być usterka w oprogramowaniu do tworzenia wykresów sieci). :-) Cieszę się że mogłem pomóc.
Paŭlo Ebermann
6
Myślę, że może to być problematyczne, jeśli ktoś wyciągnął złe zatwierdzenia, a później wyśle ​​żądanie ściągnięcia zawierające te same złe zatwierdzenia, więc zakradają się, ale do repozytorium. Czy nie byłoby bezpieczniej utworzyć nowe zatwierdzenie, które odwraca złe zmiany? W ten sposób, jeśli złe zatwierdzenia zostały przeniesione na inne gałęzie / rozwidlenia, zostaną skutecznie usunięte przez kolejne pociągnięcie do tej innej gałęzi / rozwidlenia? Nie twierdzę, że to fakt, to jest to, co myślę, że może być prawdą, będąc w tej samej pozycji co OP i spędzając około godziny na rozważaniu moich opcji.
Myles McDonnell,
4
@Czy zasugerowałbym odrzucenie tej odpowiedzi. Jest to dobre rozwiązanie dla kodu, który nie został jeszcze wciśnięty (w tym przypadku, to jest bardziej istotne pytanie SO, ale dla kodu, który jest udostępniany publicznie, wykonując polecenia git że przepisuje historię (w tym przypadku, reset --harda nacisk jest siła bardzo zła praktyka) .Odpowiedź @errordeveloper poniżej pokazuje sposób na zrobienie tego bez przepisywania historii lub forsowania na siłę.
asmeurer
34

Jeśli szarpnięcie było ostatnią rzeczą, jaką wtedy zrobił

git reset --hard HEAD~1
samthebest
źródło
3
uważaj, postępując zgodnie z tą instrukcją, w rzeczywistości cofnęło mi to 2 kroki, a nie jeden.
szeitlin
1
@szeitlin Jak to się mogło stać, że cofnąłeś się o dwa kroki, a nie jeden? Wiem, że ten komentarz został pozostawiony ponad 4 lata temu, ale jestem ciekawy, czy ktoś zna odpowiedź, jak to się może stać. To jest dla mnie bardzo ważne. Dzięki.
Haradzieniec
Nie pamiętam teraz, ale zgaduję, że mogłoby się to zdarzyć, gdybym zrobił nowy commit, kiedy próbowałem zresetować? Po prostu przetestowałbym to za pomocą fałszywego repozytorium, jeśli się o to martwisz.
szeitlin
Ten działał dobrze dla mnie. Usunął ostatnio scalone żądanie ściągnięcia. Po git reset --hard HEAD~1użyłem git push origin -fzaktualizować zdalnego repozytorium. Ale bądź ostrożny, zachowaj ostrożność, zanim to zrobisz.
Denis Oluka
24

Od 24 czerwca 2014 r. Możesz łatwo anulować żądanie ściągnięcia (zobacz „ Cofanie żądania ściągnięcia ”) za pomocą:

Przedstawiamy przycisk Cofnij

możesz łatwo cofnąć żądanie ściągnięcia w GitHub, klikając Przywróć:

https://camo.githubusercontent.com/0d3350caf2bb1cba53123ffeafc00ca702b1b164/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6c696e6b2e706e67

Zostaniesz poproszony o utworzenie nowego żądania ściągnięcia z cofniętymi zmianami:

https://camo.githubusercontent.com/973efae3cc2764fc1353885a6a45b9a518d9b78b/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6e65772d70722e706e67

Pozostaje jednak do przetestowania, czy to przywracanie używa, -mczy nie (również w przypadku przywracania połączeń)

Ale Adil H Raza dodaje w komentarzach (grudzień 2019):

Jest to oczekiwane zachowanie, utworzono nową gałąź i możesz utworzyć PR z tej nowej gałęzi do swojego master.
W ten sposób w przyszłości możesz cofnąć przywrócenie, jeśli zajdzie taka potrzeba, jest to najbezpieczniejsza opcja i nie należy bezpośrednio zmieniać pliku master.


Ostrzeżenie : Korayem zwraca uwagę w komentarzach, że:

Po przywróceniu, powiedzmy, że dokonałeś dalszych zmian w gałęzi Git i utworzyłeś nowy PR z tej samej gałęzi źródłowej / docelowej.
Zobaczysz, że PR pokazuje tylko nowe zmiany, ale nic z tego, co było przed przywróceniem .

Korayem odsyła nas do „ Github: zmiany ignorowane po przywróceniu ( git cherry-pick, git rebase) ” po więcej.

VonC
źródło
Próbowałem tego i utworzyło nową gałąź zamiast cofać PR na master?
Грозный
Dziwne. Czy mógłbyś zadać nowe pytanie, aby zilustrować to zachowanie?
VonC
jest to oczekiwane zachowanie, utworzono nową gałąź i możesz utworzyć żądanie PR z tej nowej gałęzi do swojego mastera. W ten sposób w przyszłości możesz cofnąć przywrócenie, jeśli zajdzie taka potrzeba, jest to najbezpieczniejsza opcja i nie wymaga bezpośredniej zmiany twojego mastera.
Adil H. Raza
1
@ AdilH.Raza Dziękuję. W odpowiedzi zawarłem Twój komentarz, aby uzyskać lepszą widoczność.
VonC
1
Trzymając kciuki @VonC, zaoszczędzi to programistom na całym świecie zbyt wielu cierpień i marnowania czasu
Korayem
8

Aby cofnąć żądanie ściągnięcia z Github z zatwierdzeniami, których nie chcesz usuwać, musisz uruchomić:

git reset --hard --merge <commit hash>

z hashem zatwierdzenia będącym zatwierdzeniem przed scaleniem żądania ściągnięcia. Spowoduje to usunięcie wszystkich zatwierdzeń z żądania ściągnięcia bez wpływu na jakiekolwiek zatwierdzenia w historii.

Dobrym sposobem na znalezienie tego jest przejście do teraz zamkniętego żądania ściągnięcia i znalezienie tego pola:

Obraz żądania ściągnięcia Obraz żądania ściągnięcia

Po uruchomieniu git reseturuchom:

git push origin --force <branch name>

Powinno to przywrócić gałąź z powrotem przed żądaniem ściągnięcia BEZ wpływu na jakiekolwiek zatwierdzenia w gałęzi, które są zasypywane w historii zatwierdzeń między zatwierdzeniami z żądania ściągnięcia.

EDYTOWAĆ:

Jeśli klikniesz przycisk przywracania w żądaniu ściągnięcia, spowoduje to utworzenie dodatkowego zatwierdzenia w gałęzi. NIE cofa zobowiązań ani nie rozłącza. Oznacza to, że w przypadku naciśnięcia przycisku przywracania nie można otworzyć nowego żądania ściągnięcia, aby ponownie dodać cały ten kod.

FluffySamurai
źródło
Świetny sposób na wyprostowanie rzeczy bez potrzeby szalonego odwracania lub wybierania wiśni
Cumulo Nimbus
Dzięki! To właśnie planowałem zrobić, ale byłoby to około 200 zobowiązań do wybrania.
FluffySamurai
1

Korzystam z tego miejsca cały czas, dzięki.

Szukałem, jak cofnąć żądanie ściągnięcia i dotarłem tutaj.

Miałem właśnie git reset --hard„dawno temu” i szybko cofnąć się do miejsca, w którym byłem przed wykonaniem polecenia ściągnięcia.

Oprócz szukania tutaj, zapytałem również mojego współpracownika, co zrobi, i miał zazwyczaj dobrą odpowiedź: korzystając z przykładowego wyjścia w pierwszej odpowiedzi powyżej:

git reset --hard 9271e6e

Podobnie jak w przypadku większości rzeczy w Git, jeśli robisz to w sposób, który nie jest łatwy, prawdopodobnie robisz to źle.

Mike Marshall
źródło