Muszę wyskoczyć i usunąć „środkowe” zatwierdzenie w mojej gałęzi master. Jak mogę to zrobić?

96

Na przykład w następującej gałęzi głównej muszę wyrzucić do kosza tylko zatwierdzenie af5c7bf16e6f04321f966b4231371b21475bc4da, które jest drugim z powodu poprzedniej rebase:

commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <[email protected]>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <[email protected]>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

Muszę się utrzymać

  • pierwsze zobowiązanie 60b413512e616997c8b929012cf9ca56bf5c9113,
  • trzecie zobowiązanie e6523efada4d75084e81971c4dc2aec621d45530 i
  • ostatnie zatwierdzenie 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22

„wyrzucenie” tylko drugiego zatwierdzenia af5c7bf16e6f04321f966b4231371b21475bc4da

Jak mogę to zrobić? Z góry dziękuję Luca

Luca G. Soave
źródło

Odpowiedzi:

102

Rebase lub Przywróć są opcje. Rebase faktycznie usunie zatwierdzenie z historii, więc będzie wyglądać tak, jakby drugie zatwierdzenie nigdy nie istniało. Będzie to problem, jeśli wypchnąłeś gałąź główną do innych repozytoriów. Jeśli w tym przypadku spróbujesz wypchnąć dane po rebase, git wyświetli komunikat o błędzie odrzucenia bez szybkiego łączenia do przodu .

Przywróć jest właściwym rozwiązaniem, gdy gałąź została udostępniona innym repozytoriom. git revert af5c7bf16utworzy nowe zatwierdzenie, które po prostu odwróci zmiany wprowadzone przez af5c7bf16. W ten sposób historia nie jest przepisywana, zachowujesz wyraźny zapis błędu, a inne repozytoria zaakceptują push.

Oto dobry sposób na wymazanie: git rebase -i <commit>^ prowadzi to do zatwierdzenia tuż przed tym, które chcesz usunąć. Interaktywny edytor pokaże listę wszystkich zatwierdzeń do tego momentu. Możesz wybierać, zgniatać itp. W tym przypadku usuń wiersz zatwierdzenia, który chcesz usunąć, i zapisz plik. Rebase zakończy swoją pracę.

JCotton
źródło
2
Jeśli wybiorę Rebase, jakie jest właściwe zobowiązanie do rebase? Muszę rzucić tylko drugie ...
Luca G. Soave
@ BBJ3 Zobacz odpowiedź mipadi.
Prajwal Dhatwalia
34

Jeśli rebase jest opcją, możesz zmienić bazę i po prostu ją porzucić:

$ git rebase -i 414ceffc^

Jeśli rebase nie jest opcją, możesz ją po prostu cofnąć:

$ git revert af5c7bf16
mipadi
źródło
jeśli dostanę za "git rebase 414ceffc", które jest starszym czwartym zatwierdzeniem, czy nie stracę też trzeciego e6523 i pierwszego 60b41?
Luca G. Soave
3
@Luca G. Soave: „Stracisz” zatwierdzenie tylko wtedy, gdy wyraźnie powiesz, git rebaseaby go usunąć (uruchamiając rebasew trybie interaktywnym i usuwając jego wpis).
mipadi
Dzięki mipadi, oddaję swój głos na JCotton zasadniczo za obszerne wyjaśnienie, nawet jeśli wy dwaj powiedzieliście to samo ... jeszcze raz dziękuję.
Luca G. Soave
29

Pomimo całego uznania, jakie otrzymałem tutaj od oryginalnych odpowiedzi, nie znalazłem ich w zadowalającej odpowiedzi na pytanie. Jeśli znajdziesz się w sytuacji, w której musisz usunąć zatwierdzenie lub zbiór zatwierdzeń ze środka historii, to proponuję:

  • Utwórz nową gałąź poza nagłówkiem tej zawierającej wszystkie zatwierdzenia i przełącz się na nią.
  • Przywróć nową gałąź z powrotem do punktu, od którego chcesz rozpocząć nową bazę.
  • Następnie (tutaj kluczowa kwestia) wybierz kolejne zatwierdzenia, które faktycznie chcesz zastosować później, z oryginalnej gałęzi do nowej, i pomiń zatwierdzenia, których już nie chcesz (tj. Te, które usuwasz).
  • Jeśli chcesz, zmień nazwę oryginalnej gałęzi na coś wskazującego na stary kod, a następnie zmień nazwę nowej gałęzi, tak jak nazywała się oryginalna.
  • Na koniec prześlij zmiany do zdalnego repozytorium (jeśli go używasz). Prawdopodobnie będziesz musiał użyć „wymuszonego pchnięcia”. Jeśli Twoi współpracownicy mają problemy z pobieraniem wersji, najłatwiej będzie im po prostu sklonować repozytorium ponownie ze zdalnego źródła. Tak czy inaczej, prawdopodobnie będziesz chciał z nimi porozmawiać, jeśli i tak zgrywasz commity ze środka swojej historii!

Oto informacje o Cherry Picking: Co oznacza wybieranie najlepszych zmian w git?

Oto kilka sposobów na zrobienie tego z Tortoise Git (tak jak właśnie to zrobiłem). Zdecydowanie łatwiej jest używać narzędzia GUI do tego rodzaju operacji! Cherry pick za pomocą TortoiseGit

BuvinJ
źródło
6
To powinna być najlepsza odpowiedź!
MadOgre
Fajny sposób na użycie czereśni, to rozwiązanie jest jeszcze lepsze, gdy chcesz „pominąć” więcej niż jedno zatwierdzenie.
Johnny Willer
Nie dotyczy to pierwotnego pytania. Chociaż sugerowane rozwiązanie działa, jest o wiele bardziej czasochłonne / niewygodne, a IMO nie przynosi żadnych korzyści. Jeśli gałąź została już wypchnięta (i używana na wolności), prawdopodobnie odpowiedzią jest strategia przywracania. Jeśli nie, użyłbym rebase interactive i usunięcia naruszającego commita. Jeśli został popchnięty, ale wiemy, że nie jest używany przez nikogo, nadal możesz uciec z rebase, a następnie pchnięciem siły.
raduw