Pracując z systemem kontroli wersji Git, masz dużą swobodę w sposobie pracy z commitami i gałęziami. Istnieją jednak uniwersalne praktyki, które powinieneś znać, aby utrzymać swoje repozytorium w czystości. Jak rebase może Ci w tym pomóc?

Wstęp

Rebase to strategia Gita służąca do synchronizacji pracy z gałęzią bazową (main lub dowolną inną gałęzią) poprzez przenoszenie commitów z jednego miejsca do drugiego. Może to brzmieć przerażająco, ale w rzeczywistości jest całkiem proste 😎. Przyjrzyjmy się temu w praktyce!

Z mojego doświadczenia wynika, że większość programistów stosuje strategię scalania (z użyciem merge) w celu synchronizacji pracy pomiędzy gałęziami. Jest to oczywiście prawidłowe użycie Gita, ale szybko może doprowadzić do niezłego bałaganu:

  • domyślne tytuły merge commitów nie są pomocne
  • historia Gita może stać się jednym wielkim spaghetti 😵‍💫
Historia Gita z merge commitami

Moim zdaniem rebase jest dużo lepszym rozwiązaniem. Zachowuje historię liniową, co pozwala na efektywniejsze przeglądanie commitów. Dokładnie ten sam kod (jak w przypadku pokazanej wcześniej strategii z użyciem merge) w obu gałęziach A i B można uzyskać, wykonując rebase obu gałęzi. Historia wyglądałaby tak:

Liniowa historia Gita

Jak to zrobić? Cóż, jak zawsze to zależy 🙂. W CLI możesz zmienić bazę gałęzi za pomocą prostego polecenia git rebase <target_branch>, w naszym przykładzie wyglądałoby to tak:

$ git checkout A
$ git rebase main

W PHPStorm możesz to zrobić, klikając prawym przyciskiem myszy na gałąź docelową i wybierając opcję „Rebase X na Y”. Tak naprawdę “pod maską” wykorzystanie dokładnie to samo polecenie CLI 😉.

Git rebase w PHPStorm

W efekcie otrzymasz gałąź A na górze gałęzi main. Treść commitów będzie taka sama, ale ich hashe będą inne!

Git rebase zmienia hash commitów

Rebase gałęzi zależących od siebie

Sprawy stają się nieco bardziej skomplikowane, jeśli chodzi o zmianę bazy gałęzi B. Ponieważ była ona oparta na gałęzi A przed zmianą bazy A, teraz zawiera własne commity (B1-B2) i commity ze starej gałęzi A (A1-A2). Potrzebujemy tylko B, więc jak to zrobić? --onto na ratunek 😁! Przede wszystkim potrzebujesz SHA ostatniego commita, które nie jest częścią twoich zmian. Taki commit jest bazą Twojej pracy, a teraz potrzebujesz nowej bazy — właśnie dlatego nazywa się to rebase 😁. Możesz pobrać SHA z git log, a kiedy już go masz, wystarczy wykonać polecenie:

$ git checkout B
$ git rebase --onto A <previous_base_hash>

W PHPStorm możesz uzyskać SHA commita będącego bazą, klikając go prawym przyciskiem myszy i wybierając opcję „Copy revision number” (lub używając skrótu klawiaturowego). Następnie możesz otworzyć Git → Rebase z menu, a otworzysz okno dialogowe. W sekcji „Modify options” znajdziesz opcję --onto, a kiedy ją wybierzesz, zobaczysz pole formularza umożliwiające podanie SHA poprzedniej bazy. Ostatnią rzeczą, którą musisz podać, jest gałąź docelowa (w naszym przykładzie: A).

Git rebase dialog in PHPStorm

Na marginesie: możesz zmienić bazę gałęzi w UI #gitlab, używając polecenia /rebase w komentarzu 🙂. Warto wspomnieć, że taki rebase:

  • ✅ nie usuwa approvali (ponieważ Gitlab wie, że kod jest dokładnie taki sam jak wcześniej)
  • ❌ nie podpisuje commitów kluczem GPG

Konflikty podczas zmiany bazy

Jedna istotna kwestia: kiedy użyjesz git rebase, możesz napotkać konflikty w kodzie. Ale jeśli twoja gałąź jest w konflikcie z gałęzią docelową, podczas merge wystąpi dokładnie ten sam konflikt, więc w rzeczywistości niczego to nie zmienia 🤷‍♂. Jedyna różnica polega na tym, że czasami podczas zmiany bazy trzeba wielokrotnie rozwiązać te same konflikty. To może być naprawdę irytujące 😩. Na szczęście, gdy często wykonujesz rebase i twoja gałąź jest zaktualizowana, nie zdarza się to zbyt często.

Możesz także włączyć opcję rerere w Git i spróbować skorzystać z reusing recorded resolution 🙂.

$ git config --global rerere.enabled true

Inne zalety

Istnieje kilka innych zaawansowanych opcji rebase w Git, których nie będę tutaj szczegółowo omawiał, ale oto co możesz zrobić podczas rebase:

  • Tryb --interactive pozwala modyfikować kod, zmieniać kolejność commitów, redagować tytuły, łączyć commity lub usuwać je podczas zmiany bazy. Oznacza to, że możesz od czasu do czasu posprzątać swoją gałąź, gdy będziesz robić postępy w implementacji. To sprawia, że rebase jest jeszcze ważniejszy pod względem czytelności historii Git. W PHPStorm możesz znaleźć tę opcję w oknie dialogowym Rebase, a następnie możesz wizualnie wybrać, co zrobić z każdym commitem. To naprawdę przydatne i wygodne!
  • w razie potrzeby możesz zachować merge commity, co oznacza, że możesz zmienić bazę nawet bardziej złożonych gałęzi, zachowując ich historię nienaruszoną.

Podsumowanie

Git rebase jest przeznaczony do zapewnienia liniowej historii commitów i jest alternatywą dla synchronizacji z użyciem merge. Rebase zmienia historię, ponieważ commity po rebase mają inne SHA, dlatego należy go używać głównie na etapie programowania.

Naprawdę sugeruję zapoznanie się z [dokumentacją Git rebase] (https://git-scm.com/docs/git-rebase) i wypróbowanie tego podejścia 😁. Obiecuję, że to nie jest trudne, wymaga jedynie pewnego rodzaju mentalnej zmiany 😉.

Kiedy zaczniesz go używać, nagle stanie się on Twoim najlepszym przyjacielem w Git.