Jak cofnąć zatwierdzenie scalania, które zostało już przekazane do zdalnego oddziału?

959

git revert <commit_hash>sam nie zadziała. -mnależy podać i jestem dość zdezorientowany.

Czy ktoś wcześniej tego doświadczył?

Yaz
źródło
3
Spójrz na odpowiedź na to pytanie: stackoverflow.com/questions/2318777/...
Eugen
2
Powiązane: Cofnąć scalenie Git? .
Link tutaj jest najlepszym przykładem ilustrującym cofnięcie scalonego zatwierdzenia: christianengvall.se/undo-pushed-merge-git
SK Venkat
Jest to przykład, w którym projekt gitnie pasuje do git-flow-ish przepływu pracy, którego wszyscy używają. Jeśli developwyewidencjonowałeś, oczywiście chcesz cofnąć gałąź funkcji 2-commit, która wprowadziła błąd, a nie wieloletnią wspólną gałąź programistów. To śmieszne, że trzeba to wybrać -m 1.
pkamb
2
Jeszcze jedna sugestia, która nigdy wcześniej mi się nie zdarzyła - jeśli lista zatwierdzeń jednej gałęzi jest niewielka, wygodniej będzie cofnąć poszczególne zatwierdzenia zamiast całej gałęzi zatwierdzeń.
Sridhar Sarnobat

Odpowiedzi:

1152

-mOpcja określa liczbę nadrzędną . Jest tak, ponieważ zatwierdzenie scalania ma więcej niż jednego rodzica, a Git nie wie automatycznie, który rodzic był linią główną, a który rodzic był gałęzią, którą chcesz cofnąć.

Gdy zobaczysz zatwierdzenie scalania w danych wyjściowych git log, zobaczysz jego rodziców wymienionych w wierszu, który zaczyna się od Merge:

commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: 8989ee0 7c6b236
Author: Ben James <[email protected]>
Date:   Wed Aug 17 22:49:41 2011 +0100

Merge branch 'gh-pages'

Conflicts:
    README

W tej sytuacji git revert 8f937c6 -m 1dostaniesz drzewo w takim stanie 8989ee0, w jakim ono było , i git revert -m 2przywróci je w stanie, w jakim było 7c6b236.

Aby lepiej zrozumieć identyfikatory nadrzędne, możesz uruchomić:

git log 8989ee0 

i

git log 7c6b236
Ben James
źródło
127
z dwóch liczb 8989ee0, 7c6b236, który z nich pójść. Jak mam to zrozumieć?
Arup Rakshit
12
Po przywróceniu nie sądzę, aby można było łatwo poprawić kod w gałęzi źródłowej i scalić ponownie? kernel.org/pub/software/scm/git/docs/howto/…
IsmailS
10
Podczas przeglądania Google w poszukiwaniu lepszego wyjaśnienia znalazłem ten artykuł, który moim zdaniem wykonał świetną robotę, omawiając szczegóły. Po przeczytaniu odkryłem, że tak naprawdę szukałem polecenia RESET, a następnie wymuszenia. Może pomoże komuś innemu. atlassian.com/git/tutorials/…
Funktr0n
46
@ArupRakshit, jeśli biegniesz git log 8989ee0i git log 7c6b236powinieneś znać odpowiedź.
BMW
4
git log - łączy się, aby zobaczyć wszystkie połączenia i git log --no-łączy się, aby zobaczyć historię bez połączeń. Scalenie gałęzi przenosi historię połączonych gałęzi do celu i utrudnia
rozszyfrowanie
368

Oto kompletny przykład z nadzieją, że pomoże komuś:

git revert -m 1 <commit-hash> 
git push -u origin master

Gdzie <commit-hash>znajduje się skrót zatwierdzenia scalenia, który chcesz przywrócić, a jak podano w wyjaśnieniu tej odpowiedzi , -m 1wskazuje, że chcesz powrócić do drzewa pierwszego rodzica przed scaleniem.

git revert ...Linia zasadniczo dopuszcza zmiany, natomiast druga linia sprawia, że zmiany publiczny popychając je do odległego oddziału.

Saheed
źródło
21
Wierzyłem, że git revertpolecenie już zatwierdziło utworzony obiekt zatwierdzenia. Aby tak się nie stało, trzeba wprowadzić --no-commitflagę
Delfic
2
Jak wspomniał @Delfic, zatwierdzeniem zarządza już pierwszy wiersz (potrzebowałem: wq, aby go zweryfikować), więc drugi wiersz nie jest konieczny.
eka808
1
to jest mylące. są tylko 2 linie i nie ma git commit .. czy ktoś może edytować.
Jay Random
176

Ben powiedział ci, jak cofnąć zatwierdzenie scalania, ale bardzo ważne jest, abyś zdał sobie z tego sprawę

„... oświadcza, że ​​nigdy nie będziesz chciał, aby zmiany drzewa wprowadzane przez scalanie. W rezultacie późniejsze scalenia przyniosą tylko zmiany drzewa wprowadzone przez zatwierdzenia, które nie są przodkami wcześniej cofniętego scalenia. Może to być lub nie czego chcesz.(strona podręcznika git-merge) .

Lista wiadomości article / mailing powiązany ze strony człowieka szczegóły mechanizmów i ustaleń, które są zaangażowane. Upewnij się tylko, że rozumiesz, że jeśli cofniesz zatwierdzenie scalania, nie możesz po prostu ponownie scalić gałęzi później i oczekiwać, że te same zmiany wrócą.

Ryan Stewart
źródło
80
Ale możesz cofnąć cofnięcie, aby je odzyskać, jeśli naprawdę jest potrzebne.
dalej
5
Dzięki. Bardzo przydatna jest znajomość przypadku cofania scalania - powiedzmy, z powodu błędu - a następnie ponownego łączenia całej gałęzi po naprawieniu błędu, jest częstym zjawiskiem.
Element 10
3
Jeśli jesteś podobny do mnie, a później chciałeś scalenia, możesz cofnąć przywrócenie lub wybrać zmianę, którą cofnąłeś.
UnitasBrooks
W mojej sytuacji uderzyłem w konieczność „cofnięcia cofnięcia”, aby uzyskać problem z powrotem zmian. Zbieranie wiśni może być lepszym sposobem? Spróbuję następnym razem ...
Steven Anderson
79

Możesz wykonać następujące kroki, aby przywrócić nieprawidłowe zatwierdzenie (-a) lub zresetować zdalną gałąź z powrotem do poprawnego HEAD / state.

  1. wypłata zdalnego oddziału do lokalnego repozytorium.
    git checkout development
  2. skopiuj skrót zatwierdzenia (tj. identyfikator zatwierdzenia bezpośrednio przed niewłaściwym zatwierdzeniem) z dziennika git git log -n5

    wynik:

    popełnić 7cd42475d6f95f5896b6f02e902efab0b70e8038 "Merge branch 'źle-commit' do 'rozwoju'"
    popełnienia f9a734f8f44b0b37ccea769b9a2fd774c0f0c012 "jest to błędne popełnić"
    popełnić 3779ab50e72908da92d2cfcd72256d7a09f446ba "to jest poprawna commit"

  3. zresetuj gałąź do skrótu zatwierdzenia skopiowanego w poprzednim kroku
    git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)

  4. uruchom, git statusaby wyświetlić wszystkie zmiany, które były częścią niewłaściwego zatwierdzenia.
  5. po prostu uruchom, git reset --hardaby cofnąć wszystkie te zmiany.
  6. zmuszaj lokalny oddział do zdalnej obsługi i zauważ, że twoja historia zatwierdzeń jest czysta, jak była przed zanieczyszczeniem.
    git push -f origin development
ssasi
źródło
4
co jeśli w międzyczasie 20 programistów przeprowadziło najnowsze połączenie deweloperów?
Ewoks
2
Nie wymuszałbym forsowania gałęzi programistycznej, gdy w zespole jest 20 programistów korzystających z tej gałęzi. :) W takim przypadku dobrze jest po prostu wykonać zatwierdzenie przywracania.
ssasi
4
Jest to bardzo dobre rozwiązanie, gdy pracujesz sam lub jesteś pewien, że żaden inny deweloper nie wycofał się z popełnianych przez ciebie zobowiązań
Kyle B
52
git revert -m 1 <merge-commit>
Neeraj Kumar
źródło
2
W tej odpowiedzi brakuje wielu szczegółów. Może dlatego jest dobrze.
Gustavo Straube
30

Aby utrzymać dziennik w czystości, ponieważ nic się nie wydarzyło (z pewnymi wadami tego podejścia (z powodu push-f)):

git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>

„commit-hash-before-merge” pochodzi z logu (git log) po scaleniu.

nvd
źródło
Wskazówka: jeśli robisz to w swojej firmie, możesz nie mieć pozwolenia.
eneski
3
nigdy nie rób push -fwspólnego repo
Baptiste Mille-Mathias
17

Czasami najskuteczniejszym sposobem wycofania jest wycofanie się i zastąpienie.

git log

Skorzystaj z drugiego skrótu zatwierdzenia (pełnego skrótu, tego, do którego chcesz przywrócić, przed podanym błędem), a następnie stamtąd dokonaj reorganizacji.

git checkout -b newbranch <HASH>

Następnie usuń starą gałąź, skopiuj newbranch na jego miejsce i ponownie uruchom stamtąd.

git branch -D oldbranch
git checkout -b oldbranch newbranch

Jeśli został nadany, usuń starą gałąź ze wszystkich repozytoriów, popchnij ponownie gałąź do najbardziej centralnej i pociągnij ją z powrotem do wszystkich.

ppostma1
źródło
4
Ostrzeżenie przed transmisją powinno być naprawdę wyraźniejsze na temat tego, jak okropny jest to pomysł. Spowoduje to uszkodzenie wszystkich wersji tej gałęzi i jest naprawdę przydatne, jeśli pracujesz ze zdalnym repozytorium (github / bitbucket), do którego tylko Ty masz dostęp.
RobbyD
Nie tak źle, jak spychanie zmodyfikowanych plików konfiguracyjnych w dół strumienia do produkcji. Nie ulegnie uszkodzeniu, jest to tylko rebranżacja wcześniejszego zatwierdzenia, więc jest to okrągły sposób na przeniesienie wskaźnika gałęzi do wcześniejszej wersji. Mam nadzieję, że wpłynie to tylko na lokalne repozytorium
ppostma1,
5

Jeśli chcesz cofnąć mergezatwierdzenie, oto co musisz zrobić.

  1. Najpierw sprawdź, git logaby znaleźć identyfikator zatwierdzenia scalania. Znajdziesz także wiele identyfikatorów nadrzędnych powiązanych ze scaleniem (patrz zdjęcie poniżej).

wprowadź opis zdjęcia tutaj

Zanotuj identyfikator zatwierdzenia scalania pokazany na żółto. Identyfikatory nadrzędne to te zapisane w następnym wierszu jako Merge: parent1 parent2. Teraz...

Krótka historia:

  1. Przełącz na gałąź, na której dokonano scalenia. Następnie po prostu zrób to, git revert <merge commit id> -m 1co otworzy vikonsolę do wprowadzania komunikatu zatwierdzenia. Napisz, zapisz, wyjdź, gotowe!

Długa historia:

  1. Przełącz na gałąź, na której dokonano scalenia. W moim przypadku jest to testgałąź i staram się ją usunąć feature/analytics-v3.

  2. git revertto polecenie, które cofa każde zatwierdzenie. Ale przy cofnięciu mergezatwierdzenia jest paskudna sztuczka . Musisz wpisać -mflagę, inaczej się nie powiedzie. Odtąd musisz zdecydować, czy chcesz przywrócić swój oddział i sprawić, by wyglądał dokładnie tak, jak był parent1lub parent2za pośrednictwem:

git revert <merge commit id> -m 1(wraca do parent2)

git revert <merge commit id> -m 2(wraca do parent1)

Możesz zalogować tych rodziców, aby dowiedzieć się, którą drogą chcesz iść, i to jest przyczyną całego zamieszania.

saran3h
źródło
5

Wszystkie odpowiedzi dotyczyły już większości rzeczy, ale dodam 5 centów. W skrócie cofnięcie zatwierdzenia scalania jest dość proste:

git revert -m 1 <commit-hash>

Jeśli masz uprawnienia, możesz przepchnąć je bezpośrednio do gałęzi „master”, w przeciwnym razie po prostu wypchnij je do swojej gałęzi „revert” i utwórz żądanie ściągnięcia.

Więcej przydatnych informacji na ten temat można znaleźć tutaj: https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html

xproph
źródło
1

Odkryłem, że utworzenie odwrotnej łatki między dwoma znanymi punktami końcowymi i zastosowanie tej łatki byłoby skuteczne. Zakłada się, że utworzyłeś migawki (tagi) poza gałęzią master, a nawet kopią zapasową gałęzi master, powiedz master_bk_01012017.

Powiedzmy, że gałąź kodu, którą scaliłeś w master, to mojaoddział.

  1. Mistrz kasy.
  2. Utwórz pełną binarną odwrotną łatkę między master a twoją kopią zapasową. git diff --binary master..master_bk_01012017 > ~/myrevert.patch
  3. Sprawdź poprawkę git apply --check myrevert.patch
  4. Zastosuj łatkę z podpisem git am --signoff < myrevert.patch
  5. Jeśli będziesz musiał ponownie wprowadzić ten kod, gdy zostanie on naprawiony, musisz odłączyć cofniętego mastera i sprawdzić gałąź fix git branch mycodebranch_fix git checkout mycodebranch_fix
  6. Tutaj musisz znaleźć klucz SHA do przywrócenia i przywrócić przywrócenie git revert [SHA]
  7. Teraz możesz użyć swojej poprawki mycodebranch_fix, aby naprawić problemy, zatwierdzić i ponownie połączyć w master po zakończeniu.
alexplain
źródło
1

Prawidłowo oznaczona odpowiedź działała dla mnie, ale musiałem poświęcić trochę czasu, aby ustalić, co się dzieje. Postanowiłem więc dodać odpowiedź, podając proste, proste kroki w przypadku takich przypadków jak mój.

Powiedzmy, że mamy oddziały A i B .. Połączyłeś oddział A w oddział B i odepchnąłeś oddział B do siebie, więc teraz scalenie jest jego częścią. Ale chcesz wrócić do ostatniego zatwierdzenia przed scaleniem .. Co zrobić ty robisz?

  1. Przejdź do folderu głównego git (zwykle folder projektu) i użyj git log
  2. Zobaczysz historię ostatnich zatwierdzeń - zatwierdzenia mają właściwości zatwierdzenia / autora / daty, podczas gdy scalenia mają także właściwość scalania - więc widzisz je w następujący sposób:

    commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>

  3. Użyj git log <parentHashA>i git log <parentHashB>- zobaczysz historię zatwierdzeń tych oddziałów nadrzędnych - pierwsze zatwierdzenia na liście są najnowsze

  4. Wybierz <commitHash>żądane zatwierdzenie, przejdź do folderu głównego git i użyj git checkout -b <newBranchName> <commitHash>- utworzy nowy oddział, zaczynając od ostatniego zatwierdzenia wybranego przed scaleniem. Voila, gotowe!
Божидар Йовчев
źródło
0

Problem ten napotkałem również w przypadku PR, który został połączony z gałęzią główną repozytorium GitHub.

Ponieważ chciałem po prostu zmodyfikować niektóre zmodyfikowane pliki, ale nie cały zmiany PR przyniósł musiałem z .amendmerge commitgit commit --am

Kroki:

  1. Przejdź do gałęzi, którą chcesz zmienić / przywrócić niektóre zmodyfikowane pliki
  2. Wprowadź wymagane zmiany zgodnie ze zmodyfikowanymi plikami
  3. uruchomić git add *lubgit add <file>
  4. uruchom git commit --ami sprawdź poprawność
  5. biegać git push -f

Dlaczego to interesujące:

  • Utrzymuje autor PR niezmieniony
  • Nie łamie drzewa git
  • Zostaniesz oznaczony jako osoba zatwierdzająca (autor zatwierdzenia scalania pozostanie niezmieniony)
  • Git działa tak, jakbyś rozwiązał konflikty, usunie / zmieni kod w zmodyfikowanych plikach, tak jakbyś ręcznie powiedział GitHubowi, aby nie scalał go tak, jak jest
Maxime Lafarie
źródło
0

Znalazłem dobre wyjaśnienie dotyczące sposobu cofnięcia scalenia z tego linku i skopiowałem wklejone wyjaśnienie poniżej i byłoby pomocne na wypadek, gdyby poniższy link nie działał.

Jak przywrócić wadliwe scalenie Alan ([email protected]) powiedział:

Mam gałąź główną. Mamy gałąź, nad którą pracują niektórzy programiści. Twierdzą, że jest gotowy. Scalamy go z gałęzią master. Coś psuje, więc cofamy scalanie. Wprowadzają zmiany w kodzie. doprowadzają go do punktu, w którym mówią, że jest w porządku, a my ponownie się scalamy. Po zbadaniu okazuje się, że zmiany kodu dokonane przed przywróceniem nie znajdują się w gałęzi master, ale zmiany kodu po nim są w gałęzi master. i poprosił o pomoc w wyjściu z tej sytuacji.

Historia natychmiast po „przywróceniu scalenia” wyglądałaby następująco:

---o---o---o---M---x---x---W
              /
      ---A---B

gdzie A i B znajdują się po stronie rozwoju, który nie był tak dobry, M jest scaleniem, które przenosi te przedwczesne zmiany do linii głównej, x są zmianami niezwiązanymi z tym, co zrobiła gałąź boczna i już dokonała na linii głównej, a W jest „ revert of the merge M "(czy W nie wygląda M na odwrót?). IOW, „diff W ^ .. W” jest podobne do „diff -RM ^ .. M”.

Takie „cofnięcie” scalenia można wykonać za pomocą:

$ git revert -m 1 M Po tym, jak twórcy bocznej gałęzi naprawią swoje błędy, historia może wyglądać następująco:

---o---o---o---M---x---x---W---x
              /
      ---A---B-------------------C---D

gdzie C i D mają naprawić to, co zostało zepsute w A i B, i możesz już mieć inne zmiany w linii głównej po W.

Jeśli scalisz zaktualizowaną gałąź boczną (z D na jej końcu), żadna ze zmian dokonanych w A lub B nie nastąpi, ponieważ zostały cofnięte przez W. Tak właśnie widział Alan.

Linus wyjaśnia sytuację:

Cofnięcie zwykłego zatwierdzenia po prostu skutecznie anuluje to, co zrobił, i jest dość proste. Ale cofnięcie zatwierdzenia scalania powoduje również cofnięcie danych, które zmieniło zatwierdzenie, ale nie ma absolutnie żadnego wpływu na historię , jaką miało scalenie. Zatem scalanie będzie nadal istniało i nadal będzie postrzegane jako łączenie dwóch gałęzi razem, a przyszłe połączenia zobaczą to scalenie jako ostatni wspólny stan - a przywrócenie, które odwróciło wprowadzone scalenie, nie wpłynie na to wcale. Tak więc „cofnięcie” cofa zmiany danych, ale tak naprawdę nie jest„cofnij” w tym sensie, że nie cofnie to wpływu zatwierdzenia na historię repozytorium. Jeśli więc myślisz o „cofnięciu” jako „cofnięciu”, to zawsze będziesz tęsknił za tą częścią powrotów. Tak, usuwa dane, ale nie, nie cofa historii. W takiej sytuacji powinieneś najpierw przywrócić poprzednią wersję, dzięki czemu historia wyglądałaby tak:

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

gdzie Y oznacza cofnięcie W. Takie „cofnięcie cofnięcia” można wykonać za pomocą:

$ git revert W Ta historia (ignorując możliwe konflikty między zmianami W i W..Y) byłaby równoznaczna z brakiem W lub Y w historii:

---o---o---o---M---x---x-------x----
              /
      ---A---B-------------------C---D

a ponowne połączenie gałęzi bocznej nie spowoduje konfliktu wynikającego z wcześniejszego cofnięcia i cofnięcia cofnięcia.

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

Oczywiście zmiany wprowadzone w C i D nadal mogą kolidować z tym, co zostało zrobione przez dowolny z x, ale jest to zwykły konflikt scalania.

MK446
źródło
-2

Jak wspomniał Ryan, git revertmoże to utrudnić połączenie, więc git revertmoże nie być to, czego chcesz. Zauważyłem, że użycie git reset --hard <commit-hash-prior-to-merge>polecenia jest bardziej przydatne tutaj.

Po wykonaniu części twardego resetu możesz następnie wymusić wypchnięcie do zdalnej gałęzi, czyli git push -f <remote-name> <remote-branch-name>tam, gdzie <remote-name>często jest ona nazywana origin. Od tego momentu możesz ponownie połączyć, jeśli chcesz.

Harry Wang
źródło
4
Wszystko, co wymaga użycia siły jest złym pomysłem, chyba że jesteś jedynym, który używa repozytorium i wiesz dokładnie, co robisz. Cofanie za pomocą git revert, a następnie ewentualnie cofanie za pomocą git revert (jeśli musisz przywrócić rzeczy z powrotem) jest znacznie bezpieczniejszą alternatywą.
oyvind