Przewodnik po usuwaniu błędów za pomocą Gita (część 2)
Opublikowany: 2022-03-10W tej drugiej części naszej serii „Undoing Mistakes with Git” ponownie odważnie spojrzymy niebezpieczeństwu w oczy: przygotowałem cztery nowe scenariusze końca świata — w tym oczywiście kilka sprytnych sposobów na uratowanie naszych karków! Ale zanim zagłębimy się w to: spójrz na poprzednie artykuły na Git, aby uzyskać jeszcze więcej metod samoratowania, które pomogą Ci naprawić błędy z Git!
Chodźmy!
Odzyskiwanie usuniętej gałęzi za pomocą Reflog
Czy kiedykolwiek usunąłeś gałąź i wkrótce potem zdałeś sobie sprawę, że nie powinieneś? W mało prawdopodobnym przypadku, gdy nie znasz tego uczucia, mogę ci powiedzieć, że nie jest ono dobre. Mieszanina smutku i złości wkrada się do ciebie, gdy myślisz o całej ciężkiej pracy włożonej w zmiany tej gałęzi, o całym cennym kodzie, który teraz zgubiłeś.
Na szczęście istnieje sposób na przywrócenie tej gałęzi do życia — za pomocą narzędzia Git o nazwie „Reflog”. Używaliśmy tego narzędzia w pierwszej części naszej serii, ale oto małe odświeżenie: Reflog jest jak dziennik, w którym Git odnotowuje każdy ruch wskaźnika HEAD w lokalnym repozytorium. Innymi słowy, mniej nerdowe: za każdym razem, gdy kasujesz, zatwierdzasz, scalasz, zmieniasz bazę, wybierasz wiśnie i tak dalej, tworzony jest wpis do dziennika. To sprawia, że Reflog jest idealną siatką bezpieczeństwa, gdy coś pójdzie nie tak!
Rzućmy okiem na konkretny przykład:
$ git branch * feature/login master
Widzimy, że obecnie mamy sprawdzony nasz oddział feature/login
. Powiedzmy, że to jest gałąź, którą zamierzamy usunąć (nieumyślnie). Jednak zanim to zrobimy, musimy przejść do innej gałęzi, ponieważ nie możemy usunąć naszej obecnej gałęzi HEAD!
$ git checkout master $ git branch -d feature/login
Nasza cenna gałąź funkcji już zniknęła — dam ci chwilę, aby (a) zrozumieć powagę naszego błędu i (b) trochę opłakiwać. Po otarciu łez musimy znaleźć sposób na przywrócenie tej gałęzi! Otwórzmy Reflog (po prostu wpisując git reflog
) i zobaczmy, co dla nas kryje:
Oto kilka komentarzy, które pomogą Ci zrozumieć wyniki:
- Przede wszystkim musisz wiedzieć, że Reflog sortuje swoje wpisy chronologicznie: najnowsze pozycje znajdują się na górze listy.
- Najwyższym (a zatem najnowszym) elementem jest polecenie
git checkout
, które wykonaliśmy przed usunięciem gałęzi. Jest on tutaj zarejestrowany w Reflog, ponieważ jest to jeden z tych „ruchów wskaźnika HEAD”, które Reflog tak sumiennie rejestruje. - Aby cofnąć nasz poważny błąd, możemy po prostu wrócić do stanu sprzed tego — który jest również czysto i wyraźnie odnotowany w Reflog!
Spróbujmy więc tego, tworząc nową gałąź (o nazwie naszej „zagubionej” gałęzi), która zaczyna się od tego hasha SHA-1 stanu „przed”:
$ git branch feature/login 776f8ca
I voila! Będziesz zachwycony, widząc, że teraz przywróciliśmy naszą pozornie utraconą gałąź!
Jeśli używasz graficznego interfejsu użytkownika Git, takiego jak „Tower”, możesz skorzystać ze skrótu: po prostu naciśnij CMD + Z na klawiaturze, aby cofnąć ostatnie polecenie — nawet jeśli właśnie brutalnie usunąłeś gałąź!
Przenoszenie zobowiązania do innego oddziału
W wielu zespołach istnieje zgoda, aby nie zatwierdzać długotrwałych gałęzi, takich jak main
lub develop
: gałęzie takie jak te powinny otrzymywać nowe zatwierdzenia tylko poprzez integracje (np. scalenia lub zmiany bazy). A jednak oczywiście błędy są nieuniknione: czasami zapominamy i popełniamy na tych gałęziach! Jak więc możemy posprzątać bałagan, który zrobiliśmy?
Na szczęście tego typu problemy można łatwo naprawić. Zakasajmy rękawy i zabierzmy się do pracy.
Pierwszym krokiem jest przełączenie się na właściwą gałąź docelową, a następnie przeniesienie zatwierdzenia nadmiernie za pomocą polecenia cherry-pick
:
$ git checkout feature/login $ git cherry-pick 776f8caf
Będziesz teraz mieć zatwierdzenie w żądanej gałęzi, gdzie powinno być na pierwszym miejscu. Świetny!
Pozostaje jednak jeszcze jedna rzecz do zrobienia: musimy najpierw wyczyścić gałąź, na której przypadkowo wylądowała! Polecenie cherry-pick
, że tak powiem, utworzyło kopię zatwierdzenia — ale oryginał jest nadal obecny w naszej długo działającej gałęzi:
Oznacza to, że musimy wrócić do naszej długo działającej gałęzi i użyć git reset
, aby ją usunąć:
$ git checkout main $ git reset --hard HEAD~1
Jak widać, używamy tutaj polecenia git reset
, aby usunąć wadliwe zatwierdzenie. Parametr HEAD~1
mówi Gitowi, aby „cofnął się o 1 wersję za HEAD”, skutecznie usuwając najwyższy (w naszym przypadku: niechciany) commit z historii tej gałęzi.
I voila: zatwierdzenie jest teraz tam, gdzie powinno być na pierwszym miejscu , a nasza długo działająca gałąź jest czysta — tak jakby nasz błąd nigdy się nie wydarzył!
Edycja przesłania starego zobowiązania
Zbyt łatwo jest przemycić literówkę do wiadomości o zatwierdzeniu — i odkryć ją dopiero znacznie później. W takim przypadku stara dobra opcja --amend
git commit
nie może zostać użyta do rozwiązania tego problemu, ponieważ działa tylko dla ostatniego zatwierdzenia. Aby poprawić każdy zatwierdzenie, które jest starsze, musimy skorzystać z narzędzia Git o nazwie „Interaktywna zmiana bazy”.
Najpierw musimy powiedzieć Interactive Rebase, którą część historii zatwierdzenia chcemy edytować. Odbywa się to poprzez podanie mu hasha zatwierdzenia: nadrzędnego zatwierdzenia tego, którym chcemy manipulować.
$ git rebase -i 6bcf266b
Otworzy się okno edytora. Zawiera listę wszystkich zatwierdzeń po tym, który podaliśmy jako podstawę dla interaktywnej zmiany bazy w poleceniu:
Tutaj ważne jest, abyś nie podążał za pierwszym impulsem: w tym kroku nie edytujemy jeszcze komunikatu o zatwierdzeniu. Zamiast tego mówimy Gitowi, jakiego rodzaju manipulację chcemy wykonać, z jakim(i) zatwierdzeniem(ami). Całkiem wygodnie, na dole tego okna w komentarzach znajduje się lista słów kluczowych działań. W naszym przypadku oznaczamy wiersz #1 za pomocą reword
(zastępując w ten sposób standardowy pick
).
Wszystko, co pozostało do zrobienia w tym kroku, to zapisanie i zamknięcie okna edytora. W zamian otworzy się nowe okno edytora, które zawiera aktualną wiadomość o zatwierdzeniu, które oznaczyliśmy. A teraz wreszcie nadszedł czas na wprowadzenie zmian!
Oto cały proces w skrócie:
Korygowanie złamanego zobowiązania (w bardzo elegancki sposób)
Na koniec przyjrzymy się fixup
, szwajcarskiemu scyzorykowi narzędzi do cofania. Mówiąc prościej, pozwala to naprawić zepsute/niekompletne/niepoprawne zatwierdzenie po fakcie. To naprawdę wspaniałe narzędzie z dwóch powodów:
- Nie ma znaczenia, jaki jest problem.
Być może zapomniałeś dodać plik, powinieneś coś usunąć, wprowadzić nieprawidłową zmianę lub po prostu popełnić literówkę.fixup
działa we wszystkich tych sytuacjach! - Jest niezwykle elegancki.
Naszą normalną, instynktowną reakcją na błąd w zatwierdzeniu jest utworzenie nowego zatwierdzenia, które rozwiąże problem. Ten sposób pracy, jakkolwiek intuicyjny może się wydawać, sprawi, że Twoja historia zatwierdzeń będzie wyglądała bardzo szybko, bardzo chaotycznie. Masz „oryginalne” zatwierdzenia, a następnie te małe „zapasowe” zatwierdzenia, które naprawiają rzeczy, które poszły nie tak w oryginalnych zatwierdzeniach. Twoja historia jest zaśmiecona małymi, bezsensownymi zatwierdzeniami bandy, co sprawia, że trudno jest zrozumieć, co wydarzyło się w Twojej bazie kodu.
W tym miejscu pojawia się fixup
. Pozwala to na wykonanie tego poprawiającego zatwierdzenia bandaży. Ale tu pojawia się magia: następnie stosuje go do oryginalnego, zepsutego zatwierdzenia (naprawiając go w ten sposób), a następnie całkowicie odrzuca brzydki zatwierdzenie opatrunku!
Możemy razem przejść przez praktyczny przykład! Załóżmy, że wybrany tutaj zatwierdzenie jest zepsuty.
Powiedzmy też , że przygotowałem zmiany w pliku o nazwie error.html
, które rozwiążą problem. Oto pierwszy krok, który musimy zrobić:
$ git add error.html $ git commit --fixup 2b504bee
Tworzymy nowe zatwierdzenie, ale mówimy Gitowi, że jest to specjalne zatwierdzenie: jest to poprawka dla starego zatwierdzenia z określonym hashem SHA-1 (w tym przypadku 2b504bee
).
Drugim krokiem jest teraz rozpoczęcie sesji Interactive fixup
— ponieważ naprawa należy do dużego zestawu narzędzi Interactive Rebase.
$ git rebase -i --autosquash 0023cddd
Na temat tego polecenia warto wyjaśnić dwie rzeczy. Po pierwsze, dlaczego podałem tutaj 0023cddd
jako skrót wersji? Ponieważ musimy rozpocząć naszą sesję Interactive Rebase od zatwierdzenia rodzicielskiego naszego zepsutego kolegi.
Po drugie, do czego służy opcja --autosquash
? To zabiera nam dużo pracy! W oknie edytora, które się teraz otwiera, wszystko jest już dla nas przygotowane:
Dzięki opcji --autosquash
, Git wykonał już dla nas ciężkie podnoszenie:
- Oznaczyło to nasze małe zatwierdzenie opatrunku za pomocą słowa kluczowego
fixup
action. W ten sposób Git połączy go z zatwierdzeniem bezpośrednio powyżej , a następnie odrzuci go. - Zmienił również odpowiednio kolejność wierszy, przesuwając nasze zatwierdzenie opatrunkowe bezpośrednio pod zatwierdzenie, które chcemy naprawić (ponownie:
fixup
działa poprzez połączenie zatwierdzenia oznaczonego z tym powyżej !).
W skrócie: nie pozostaje nam nic innego jak zamknąć okno!
Przyjrzyjmy się końcowemu efektowi.
- Poprzednio zepsuty zatwierdzenie jest naprawione: teraz zawiera zmiany, które przygotowaliśmy w naszym zatwierdzeniu opatrunku.
- Samo brzydkie zatwierdzenie opatrunku zostało odrzucone: historia zatwierdzeń jest czysta i łatwa do odczytania — tak jakby w ogóle nie wystąpił żaden błąd.
Umiejętność cofania błędów to supermoc
Gratulacje! Teraz jesteś w stanie uratować szyję w wielu trudnych sytuacjach! Nie możemy tak naprawdę uniknąć takich sytuacji: bez względu na to, jak bardzo jesteśmy doświadczeni jako programiści, błędy są po prostu częścią pracy. Ale teraz, kiedy już wiesz, jak sobie z nimi radzić, możesz stawić im czoła z wyluzowanym tętnem.
Jeśli chcesz dowiedzieć się więcej o usuwaniu błędów z Git, mogę polecić darmowy „Apteczka pierwszej pomocy dla Git”, serię krótkich filmów o dokładnie tym temacie.
Baw się, popełniając błędy — i oczywiście z łatwością je usuwając!