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 <luca.soave@gmail.com>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <luca.soave@gmail.com>
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

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ę.


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

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


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.