Jakiś czas temu, pisałem o różnicach między Rebase oraz Merge. Dzisiaj chciałbym rozważyć kilka scenariuszy, gdzie można stosować Rebase.
Przede wszystkim jeśli różnica nie jest jasna, wtedy zawsze bezpieczniejszą opcją jest Merge. Nie ma w tym nic złego i najwyżej historia logów będzie mniej czytelna, ale przynajmniej uniknie się niepotrzebnych problemów.
Zacznijmy od scenariusza kiedy nie używać rebase. W skrócie nie należy stosować rebase na publicznych gałęziach, gdzie nadpisane zmiany, mogą być u kogoś już w lokalnym repozytorium. Rozważmy diagram z poprzedniego wpisu. Po zmianach w feature branch, uzyskaliśmy następującą strukturę:
Po dokonaniu rebase na master, zmiany 4 oraz 5 zostaną przepisane:
Widzimy, że zostały one przesunięte. Techniczne będą miały zupełnie inny hash code. Problem jest taki, że cześć użytkowników mogła już pobrać kod przed dokonaniem rebase. Nie trudno domyślić się, że w momencie kiedy będą chcieli wykonać GIT PUSH, nastąpią problemy ponieważ commity 4 i 5 w ich wersji będą inne niż te na serwerze, ponieważ zostały one przepisane za pomocą Rebase. Innymi słowy zmiany 4 i 5 są inne niż te co mają pozostali użytkownicy. Skoro gałąź jest publiczna może to utrudnić życie wielu użytkownikom.
Wniosek taki, że jeśli chcemy przenieść zmiany z feature branch do master, która jest publiczną gałęzią należy używać komendy MERGE.
Rozważmy inny teraz kierunek, a mianowicie master->feature branch. Załóżmy, że tworzymy gałąź, z której nikt dalej nie będzie “branchować” ponownie. Innymi słowy zmiany w feature branch będą zsynchronizowane wyłącznie z master. W takim przypadku, użycie rebase, aby pobrać zmiany z master jest bezpieczne i dzięki niemu mamy prostą i liniową historie zmian. Oczywiście znów zostaną nadpisane commity, ale będą to wyłącznie nasze zmiany, które nie są jeszcze dostępne w publicznej gałęzi. Nie ma w tym przypadku znaczenia to, że hash code zostanie zmodyfikowany. W sytuacji jednak, gdy kilka osób pracuję nad tym samym feature branch, wtedy napotkamy identyczne problemy jak na powyższym rysunku. Oznacza to, że wtedy należy korzystać z merge. Innymi słowy, gałąź publiczna + rozwidlenia wykluczają użycie rebase. Często jednak feature branch ma charakter bardziej prywatny i wtedy nic nie stoi na przeszkodzie, aby cieszyć się prostą historią zmian wykonaną przez rebase.
Kolejny przykład to współdzielenie tej samej gałęzi. Czasami programiści pracują po prostu na master, ewentualnie osobnej gałęzi. W tym przypadku również można rozważyć rebase i jest to bezpieczna opcja. Dlaczego? W końcu pracujemy na publicznej gałęzi, a jak wiemy już rebase+publiczna gałąź zwykle jest bardzo złym pomysłem. W tym przypadku jednak, będziemy nadpisywać wyłącznie swoje własne commity, które nie są jeszcze publiczne. Jedyną przeszkodzą może być sytuacja, w które współdzielimy nasz commit za pomocą np. plików zmian. Jeśli to zrobimy, wtedy w przypadku rebase zostaną one przepisane i ta osoba, która otrzymała wcześniej od nas zmiany (np. poprzez email) będzie miała inne zmiany niż te po dokonaniu REBASE. Jeszcze raz podkreślam mowa tutaj o publicznej, współdzielonej gałęzi, która jednak nie ma żadnych rozwidleń. Wtedy mamy pewność, że dokonując rebase możemy jedynie przepisać własne, lokalne zmiany.
Podsumowując:
1. Feature branch –> master: merge
2. Master->Feature branch (w celu synchronizacji) –> rebase jest w porządku o ile, ktoś nie korzysta ze wspomnianej gałęzi np. poprzez dalsze rozwidlanie. W przeciwnym wypadku zalecany jest merge ponieważ mogą nastąpić podobne problemy jak w punkcie 1.
3. Gałęzie współdzielone (brak rozwidleń): rebase
W celu uzyskania liniowej historii można też użyć merge z parametrem fast forward. Jeśli nie będzie konfliktów, to nie zostanie utworzony merge commit.
Świetny wpis. W końcu dobrze zrozumiałem jakie konsekwencje może ze sobą nieść nieprawidłowe korzystanie z rebase.