Jak „cofnąć” przywrócone zatwierdzenie Git?

485

Biorąc pod uwagę zmianę, która została zatwierdzona przy użyciu commit, a następnie cofnięta przy użyciu revert, jaki jest najlepszy sposób na cofnięcie tego cofnięcia?

Najlepiej byłoby to zrobić z nowym zatwierdzeniem, aby nie ponownie zapisywać historii.

JimmidyJoo
źródło
4
Możliwy duplikat Jak naprawić przywrócony git commit?
phuclv
@ phuclv komentarz do możliwego duplikatu tam, wskazuje tutaj. Trzeba oznaczyć oryginał i duplikat
John Demetriou
@JohnDemetriou nie pytanie, które ma lepszy zestaw odpowiedzi powinno być otwarte. Czas nie ma tu znaczenia. Jak rozwiązywać zduplikowane pytania?
phuclv
Nie mówiłem o czasie. Właśnie skomentowałem jedną z dwóch kwestii
John Demetriou

Odpowiedzi:

385

Jeśli jeszcze nie wprowadziłeś tej zmiany, git reset --hard HEAD^

W przeciwnym razie cofnięcie przywracania jest całkowicie w porządku.

Innym sposobem jest git checkout HEAD^^ -- .i wtedy git add -A && git commit.

Adam Dymitruk
źródło
8
Zauważ, że jeśli chcesz cofnąć przywracanie bez natychmiastowego zastosowania oryginalnych zmian w gałęzi głównej, możesz (1) przywrócić oryginalną gałąź, jeśli zostanie ona usunięta, (2) kliknij „przywróć” na gałęzi przywrócenia, jak zauważył Adam, a następnie ( 3) kliknij „edytuj” w nagłówku wynikowego PR i zmień gałąź docelową na gałąź oryginalną zamiast głównej. Teraz oryginalną gałąź można ponownie scalić, aby wprowadzić poprzednio cofnięte zmiany.
pauljm
1
Pamiętaj, że spowoduje to usunięcie wszystkich zmian w działającym drzewie i indeksie. Użyj git stash, aby zapisać wszelkie zmiany, których nie chcesz stracić.
zpon
3
Jaka jest zaleta metody realizacji transakcji i zatwierdzania? Wydaje się, że w ogólnym przypadku git cherry-picklub alternatywnie git revertsą to najprostsze sposoby cofnięcia cofnięcia.
Robert Jack Will
5
Myślę, że pomocne byłoby pokazanie:, Otherwise, reverting the revert is perfectly fine.a następnie wyjaśnienie, co git checkout HEAD^^ -- .się dzieje.
Todd
3
Dobry Boże, nie używaj git add -A... chyba że chcesz dodać każdy plik do kontroli wersji, co najprawdopodobniej nie jest tym, czego chcesz.
Kaitain
473

git cherry-pick <original commit sha>
Wykona kopię oryginalnego zatwierdzenia, zasadniczo ponownie stosując zatwierdzenie

Cofnięcie cofnięcia spowoduje to samo, z komunikatem zatwierdzania przez program Messier:
git revert <commit sha of the revert>

Każdy z tych sposobów pozwoli ci git pushbez zastępowania historii, ponieważ tworzy ona nowe zatwierdzenie po przywróceniu.
Podczas wpisywania zatwierdzenia sha zwykle potrzebujesz tylko pierwszych 5 lub 6 znaków:
git cherry-pick 6bfabc

Stephan
źródło
60
Jest to z pewnością najbardziej eleganckie i kompletne rozwiązanie pytania PO. Znacznie lepsza niż zaakceptowana odpowiedź z jej założeniami, że cofnięcie zatwierdzenia znajduje się na GŁOWIE drzewa zatwierdzeń. Operator poprosił również o rozwiązanie, które nie przepisuje historii, więc trudne rozwiązanie oferowane w przyjętej odpowiedzi jest po prostu złe.
Timo,
6
@ Timo Aby wyjaśnić, zaakceptowana odpowiedź zawiera zastosowane przeze mnie rozwiązanie („cofnięcie cofnięcia”) i została opublikowana w ciągu kilku godzin od mojego pytania - jasne 3 lata wcześniej niż ta odpowiedź. Stąd znacznik wyboru.
JimmidyJoo
6
@JimmidyJoo Wiem, że spóźniłem się 3 lata, chciałem tylko, żeby ludzie przychodzili tutaj z wyszukiwarki Google, aby zobaczyć lepszą odpowiedź
Stephan
2
@Stephan Tak, ale jeszcze raz, aby wyjaśnić - to lepsza odpowiedź, ale nie ta, której użyłem do rozwiązania mojego problemu. Po prostu komentowałem, dlaczego znak wyboru jest tam, gdzie jest. Pytanie do wszystkich: czy konwencja SO nakazuje „zachować” moje poprzednie pytania i ponownie przypisywać znaczniki wyboru, gdy pojawiają się nowe odpowiedzi?
JimmidyJoo,
3
@JimmidyJoo Nie mam pojęcia o konwencji SO. Ale jako wyszukiwarka google naprawdę wolę sprawdzać lepszą odpowiedź. I byłby wdzięczny za wysiłki każdego, aby zachować swoje poprzednie pytania.
Paiman Roointan
28

Cofnięcie zatwierdzenia jest jak każde inne zatwierdzenie w git. Czyli możesz to cofnąć, jak w:

git revert 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746

Ma to oczywiście sens dopiero po wprowadzeniu zmian, a zwłaszcza wtedy, gdy nie można wymusić wypchnięcia gałęzi docelowej (co jest dobrym pomysłem na gałęzi głównej ). Jeśli zmiana nie została wprowadzona, po prostu wybierz polecenie „wiśnia”, cofnij lub po prostu usuń zatwierdzenie przywrócenia, jak w przypadku innych postów.

W naszym zespole mamy zasadę korzystania z cofania w zatwierdzeniach Revert, które zostały popełnione w głównej gałęzi, przede wszystkim w celu utrzymania historii w czystości, abyś mógł zobaczyć, które zatwierdzenie przywraca co:

      7963f4b2a9d   Revert "Revert "OD-9033 parallel reporting configuration"
      "This reverts commit a0e5e86d3b66cf206ae98a9c989f649eeba7965f.
                    ...
     a0e5e86d3b6    Revert "OD-9055 paralel reporting configuration"
     This reverts commit 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746.
                ...
     Merge pull request parallel_reporting_dbs to master* commit 
    '648d7d808bc1bca6dbf72d93bf3da7c65a9bd746'

W ten sposób możesz prześledzić historię i odkryć całą historię, a nawet ci bez wiedzy o spuściźnie mogliby sami to wypracować. Natomiast jeśli wybierzesz wiśni lub rebase rzeczy, to cenna informacja jest tracona (chyba, że włączenie go w komentarzu).

Oczywiście, jeśli zatwierdzenie cofnęło się i cofnęło więcej niż raz, staje się to dość nieuporządkowane.

Nestor Milyaev
źródło
14

Cofnięcie cofnięcia załatwi sprawę

Na przykład,

Jeśli abcdefjest to twoje zatwierdzenie i ghijkljest to potwierdzenie, które masz po cofnięciu zatwierdzenia abcdef, uruchom:

git revert ghijkl

Spowoduje to cofnięcie cofnięcia

rafee_que_
źródło
4

Dla mnie to wygląda głupio. Byłem jednak w tej samej sytuacji i cofnąłem się, aby wycofać zatwierdzenia. Zrobiłem liczbę zmian, więc musiałem cofać dla każdego „cofnięcia zatwierdzenia”.

Teraz moja historia zobowiązań wygląda trochę dziwnie.

dziwna historia

To jest projekt dla zwierząt, więc jest OK. Ale w przypadku projektu z prawdziwego życia wolałbym przejść do ostatniego zatwierdzenia przed przywróceniem przywrócić cały przywrócony kod razem w jednym zatwierdzeniu i bardziej rozsądnym komentarzu.

RredCat
źródło
4
Możesz być zainteresowany odpowiedziami na inne moje pytanie: stackoverflow.com/questions/10415565/…
JimmidyJoo
2
Można uniknąć auto popełnić i wybierz zobowiązać wiadomość używając --no-commit flagę podczas powrotu, a następnie popełnić z odpowiednim komunikatem
David Barda
Możesz także podać wiele identyfikatorów zatwierdzeń, gdy używasz git revert (myślę, że muszą być w odpowiedniej kolejności).
Aalex Gabi
Czy mogę to zrobić z pulpitu github?
Guillaume F.,
4

Oto jak to zrobiłem:
jeśli gałąź my_branchnamezostała uwzględniona w scaleniu, które zostało cofnięte. I chciałem cofnąćmy_branchname :

Najpierw robię git checkout -b my_new_branchnameod my_branchname.
Następnie robię, git reset --soft $COMMIT_HASHgdzie $COMMIT_HASHjest hash zatwierdzenia zatwierdzenia tuż przed pierwszym zatwierdzeniem my_branchname(patrz git log).
Następnie dokonuję nowego zatwierdzenia, a git commit -m "Add back reverted changes"
następnie wypycham nowy oddział, a git push origin new_branchname
następnie wysłałem żądanie ściągnięcia dla nowego oddziału.

Drew LeSueur
źródło
To droga, gdy jest zbyt wiele do wybrania. Nie rozumiem, dlaczego ta odpowiedź ma tak mało pozytywnych opinii
Fundhor
2

Lub możesz git checkout -b <new-branch>i git cherry-pick <commit>wcześniej do i git rebaseupuścić revertzatwierdzenia. wyślij żądanie ściągnięcia jak poprzednio.

Ryan Chou
źródło
1

Jeśli nie podoba ci się pomysł „cofnięcia przywrócenia” (szczególnie gdy oznacza to utratę informacji historycznych dla wielu zatwierdzeń), zawsze możesz udać się do dokumentacji git na temat „Przywracania błędnego scalenia” .

Biorąc pod uwagę następującą sytuację wyjściową

 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E   <-- fixed-up topic branch

(W to początkowe cofnięcie scalenia M; D i E są poprawkami do początkowo uszkodzonej gałęzi / zatwierdzenia funkcji)

Teraz możesz po prostu odtwarzać zmiany od A do E, aby żadne z nich nie „należało” do odwróconego scalenia:

$ git checkout E
$ git rebase --no-ff P

Nowa kopia oddziału może teraz zostać masterponownie połączona z :

   A'---B'---C'------------D'---E'  <-- recreated topic branch
  /
 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E
NobodysNightmare
źródło
Dobry pomysł i dzięki za link do dokumentu. Zwykle dokonujemy zmiany bazy za pomocą master przed ponownym połączeniem, ale git wydaje się rozpoznawać, że A ', B', C 'są takie same jak przedtem, a teraz mam D, E po W ( pastebin ). Sugestie, jak to rozwiązać?
Kristoffer Bakkejord
0

Aby odzyskać zmiany etapowe i etapowe, które zostały cofnięte po zatwierdzeniu:

git reset HEAD@{1}

Aby odzyskać wszystkie nieetapowe usunięcia:

git ls-files -d | xargs git checkout --
Richa Goyal
źródło