Sytuacja kobiet w IT w 2024 roku
16.02.20216 min
Richard Miles

Richard MilesSenior DeveloperAtheneum

Jak git rebase pomoże Ci posprzątać w commitach

Dowiedz się, jak możesz sprawić, aby Twoje commity były o wiele bardziej klarowne, używając do tego git rebase.

Jak git rebase pomoże Ci posprzątać w commitach

Czy widzieliście kiedyś coś takiego?

(wybaczcie dobór kolorów)


Ja widziałem, i wiecie co? Takie commity są do bani. Patrząc od góry: zaczęło się w miarę dobrze - mamy tutaj obowiązkowy initial commit. Potem widzimy prefiksy feat oraz fix, co jeszcze jest w miarę, ale przy sekcji deploy code to staging zaczynam się frustrować. 

10 commitów w projekcie i już robi się bałagan. To, że kod nie działa tak, jak tego chcemy, jest normalne i czasem się zdarza- nie pokazujmy jednak naszej frustracji w historii commitów. 

Jak możemy tego uniknąć?

Moglibyśmy unikać popełniania jakichkolwiek błędów, albo być kreatywni i zamaskować rzeczywistość - czyli to, że nasza gałąź jest w katastrofalnym stanie i być może kiedyś uda się to naprawić. Oba te rozwiązania nie są niestety idealne. 

Istnieje jednak trzecia opcja, która jest o wiele lepsza - możemy zmienić coś w historii commitów i sprawić, że będą one o wiele bardziej klarowne. 

Po co zmieniać historię? Lepiej zmienić teraźniejszość

Klarowność to inaczej grupowanie funkcji w logiczny sposób oraz pisanie lepszych, bardziej przejrzystych i spójnych tytułów commitów. 

Dlaczego tak zależy nam na klarowności?

  • Łatwiej wdrożyć kolejne funkcje, gdy powiązane commity są pogrupowane.
  • Kontrola historii commitów oraz tradycyjne użycie git rebase, które umieszcza commity w innych gałęziach (więcej informacji tutaj). Gdy połączymy te dwa podejścia, to będziemy mieli w zanadrzu bardzo użyteczne narzędzie. 
  • Łatwiej się zorientować w historii, gdy mamy do czynienia ze spójnymi tytułami kolejnych commitów. Będzie to plus zarówno dla Ciebie, jak i dla osoby, która sprawdza kod.
  • Tworzy dobre nawyki podczas tworzenia funkcji: pisanie klarownych tytułów commitów sprawia, że funkcje dodajemy w sposób spójny, domyślnie łącząc ze sobą części kodu - w taki sposób git rebase używamy tylko tam, gdzie to naprawdę konieczne. Od kiedy zacząłem tak robić, o wiele rzadziej wykonuję rebase’a, ponieważ moje tytuły commitów są od razu bardziej czytelne. 

Praktyczny przykład

Zakładam, że macie w swoim terminalu/cmd zainstalowanego Gita. Zakładam również, że rozumiecie, jak działają podstawowe komendy Gita, takie jak add/commit/push, i umiecie edytować pliki w wierszu poleceń (zwykle w VIM). Kilka ważnych rzeczy, zanim zaczniemy wykonywać rebase. 


Członkowie teamu muszą wiedzieć, dlaczego wykonujesz rebase’a

To bardzo istotne, ponieważ muszą oni wtedy szczególnie uważać podczas pracy na Twoich gałęziach. 

Zanim Twoi współpracownicy dokonają scalenia lub odłączą gałąź od czegoś, nad czym obecnie pracujesz, to powinni sprawdzić, czy nie wykonujesz tam właśnie rebase’a.  

Albo inaczej: jeśli wysyłasz do zdalnego repozytorium gałąź po wykonaniu rebase’a, którą ktoś inny już wcześniej wysyłał, to zmiany, które wprowadził Twój współpracownik, znikną. 

To właśnie dlatego oddzielam swoje własne gałęzie i wysyłam je po wykonaniu rebase’a tylko jeśli wiem, że jestem jedyną osobą, która nad nimi pracowała.  

Zawsze mogę tworzyć tymczasowe gałęzie, które można scalić z gałęziami oznaczonymi jako „feature" później. Jest to „złota zasada” wykonywania rebase’a. 


Śledź zmiany (co zostało zrobione, a co nie)

Polecam używanie takich systemów, jak Jira, Trello lub GitHub Projects do mapowania funkcji, czy pull requestów, podczas pracy na feature branch. Będzie to głównie pomagać w śledzeniu, co zostało zrobione, a co nie. 

Raczej nie chcemy sytuacji, w których wykonana przez nas praca przepadnie przez to, że wykonujemy rebase’a. Przydatne jest więc posiadanie na zewnątrz Gita innej metody, która będzie śledzić, czy zaszły zmiany. 

Jeśli ewentualnie musisz cofnąć się w pracy na potrzeby refactoringu, to istotne jest, aby śledzić jakiekolwiek zmiany poza kontrolą wersji - Git nie ma spójnej historii zmian podczas wykonywania rebase’a. 

Robienie porządku w opisach

W logu, który widzieliście na początku tego artykułu, mamy w sumie 10 commitów. W zależności od sytuacji możemy spróbować jakoś inaczej podzielić te commity, co może oznaczać przeredagowywanie, przeniesienie lub całkowite usunięcie commita. 

Każda z tych trzech rzeczy będzie od nas wymagać następującej akcji w terminalu. 

git rebase -i HEAD~9


Przyjrzymy się temu dokładniej: 

git rebase - daje naszemu terminalowi znać, że uruchamiamy Git z komendą rebase

-i - każe git rebase uruchomić się w trybie interaktywnym (w domyślnym edytorze dla Gita) 

HEAD~9 - chcemy mieć możliwość wykonania rebase’a na 9 poprzednich commitach (nie chcemy zmieniać pierwotnego tytułu). 


Po uruchomieniu zobaczymy plik w VIM (lub w jakimkolwiek innym edytorze wiersza poleceń), który zawiera listę naszych commitów, a także niektóre opcje, które możemy zastosować w każdym z nich (domyślną opcją jest pick - co oznacza, że wybieramy jakiś commit w jego obecnym stanie).


Tutaj zajmę się jedynie opcjami drop, reword oraz fixup


drop

Na potrzeby tego przykładu pozbyłem się commitu FFS - nie jest on tutaj za bardzo potrzebny, ponieważ I hope this one works rozwiązuje problem, o czym nie wiedziałem na początku. 

Możemy to zrobić przez zastąpienie pick przez drop, gdy zapiszemy i wyjdziemy z pliku, commit FFS zostanie usunięty.


Jeśli spojrzymy teraz na nasz log (w kodzie git log), to zobaczymy, że naszego commita oraz jakiegokolwiek kodu powiązanego z FFS już nie ma.


fixup oraz reword

Lubię korzystać z fixup, kiedy łączę kilka commitów w jeden - dzieje się tak w przypadku, gdy każdy z nich jest do siebie bardzo podobny. Mogę też lepiej opisać grupę funkcji, która będzie miała więcej sensu jako jeden tytuł. 

Wróćmy do wykonywania rebase’a w trybie interaktywnym, uruchamiając:

git rebase -i HEAD~8


Usunąwszy z historii FFS, mamy 8 commitów. Dokonałem jeszcze kilku zmian w pliku. 


Linijki 1 i 2 mogłyby być oddzielnymi commitami. Są raczej zrozumiałe i specjalnie je dodano, aby opisać stan projektu. 

Linijki 3 oraz 4 to błędy, a więc uruchomiłem dla nich fixup. Przenosi to kod do najbliższego wcześniejszego commita, usuwając ich tytuły - w tym przypadku chodzi o feat: added api endpoint for adding blogpost (komenda squash jest podobna do fixup, z tym wyjątkiem, że zachowuje informacje o przeniesionym commicie).  

Zamierzam scalić linijki 6, 7 oraz 8 w jeden commit o nazwie deployment przy pomocy komendy fixup. 

Nie podoba mi się sformułowanie linijki 5. Przeredaguję ją więc na coś, co lepiej przekazuje sens tego commita (oraz pozostałych, których treść została przeniesiona do tego jednego). Zapisujemy i wychodzimy z pliku, co wywoła nową instancję edytora - zostaniemy wtedy zapytani, co chcemy przeredagować w opisie commita w linijce 5. 

Jeśli chcielibyśmy przeredagować więcej, niż jeden commit przy wykonywaniu interaktywnego rebase’a, to taka sytuacja powtórzy się kilka razy. Zaktualizuj opis commita, zapisz i wyjdź z VIM. Uruchomimy teraz git log, aby sprawdzić, czy wszystko potoczyło się, tak jak chcieliśmy: 


Świetnie! Wygląda na to, że nareszcie mamy porządek.

Używaj flagi force, gdy wysyłasz coś z powrotem do zewnętrznej gałęzi git (git push origin -f), aby dać znać, że chcesz nadpisać historię. 

Git nie lubi, gdy wykonujemy to bez potwierdzenia. Działaj tak, jakbyś spodziewał się, że przy wykonywaniu rebase’a pojawią się problemy (zwłaszcza w przypadku, gdy w tej samej gałęzi pracuje więcej niż jedna osoba, kiedy trzeba postępować bardzo ostrożnie).  

Podsumowanie

Wykonywanie rebase’a to bardzo przydatna czynność, którą powinno się wykonywać z należytą ostrożnością - działa ona jednak bardzo efektywnie w kontekście tego artykułu. 

Jeśli chcesz ją wykorzystać w swoim projekcie, polecam zapoznanie się z dokumentacją tutaj


Oryginał tekstu w języku angielskim możesz przeczytać tutaj.

<p>Loading...</p>