Zaprzyjaźnij się z Git rebase

Czemu rebase jest ciekawym tematem?

Komenda git rebase ma opinię zaawansowanej i trudnej w użyciu. Moim zdaniem taka interpretacja jest bardzo szkodliwa. Jest to operacja, która powinna być wykładana na samym początku nauki cyklu pracy z Git. Jej użycie ma wiele plusów i jest wręcz konieczne, by zachować czyste repozytorium kodu.

Dlaczego w ogóle potrzebujemy tej komendy?

Zacznijmy od tego, jak zwykle przebiega proces pracy z Git. Załóżmy, że master to nasza główna gałąź, do której idą aktualne zmiany:

Prosta gałąź master.

Nasze zadanie polega na dodaniu nowej funkcjonalności. Zgodnie z najlepszymi praktykami powinniśmy zrobić odrębną gałąź np. feature. Odbijamy własną kopię kodu od master i zaczynamy nasze zmiany:

Nowa gałąź feature wychodząca z master.

Wszystko do tej pory jest w porządku. Problem zaczyna się, kiedy chcemy w końcu scalić nasze zmiany z master:

Próba scalenia gałęzi feature z master.

Co jeśli zmiany z master dotyczą tych samych części kodu? Taka sytuacja zwana jest konfliktem kodu. Automatyczne scalenie kodu staje się niemożliwe i musimy spróbować czegoś innego.

Ratunek w rebase

Rebase rozwiązuje konflikt pomiędzy gałęziami poprzez zamianę starej bazy feature na najnowszą z master.

Początek procesu rebase.

Następnie nakłada zmiany, które zostały dokonane w feature. Końcowy wynik jest zupełnie taki, jakby feature od samego początku wychodził z najnowszej wersji master.

Stan gałęzi po rebase.

Podczas procesu git pauzuje rebase jeśli natrafi na konflikt kodu. Pozwala nam to na spokojne scalanie zmiana po zmianie.

Wyższość rebase nad merge

Dlaczego jest to rozwiązanie znacznie lepsze? Jest wiele powodów, jednak ten jest najważniejszy:

Rebase nie zostawia żadnych śmieci w repozytorium

Efekt końcowy wygląda tak, jakby feature od zawsze bazowała na najnowszym masterze. Merge natomiast zostawiłoby dwa rodzaje śmieci:

  • zmiany bazujące na starym masterze, które są z nim skonfliktowane,
  • “merge commit”, czyli commit, który godzi stare zmiany z feature z najnowszym master
Rebase pozwala na rozwiązywanie konfliktów zmiana po zmianie

Podczas rebase zmiany nakładane są po kolei. Daje nam to okazję rozwiązywać konflikty w najprostszy sposób. W przypadku merge wszystkie konflikty rozwiązujemy “na raz”. Natomiast, przy dużych zmianach może być to bardzo trudne i żmudne.

Rebase pozwala na zmianę liczby/struktury commitów

Rebase zmienia bazę gałęzi i tworzy ją na nowo. Daje nam to okazję do ewentualnego posprzątania w commitach. Możemy rozbić je na mniejsze, lub scalić w jeden (co nazywamy “commit squash”). Merge nie daje nam do tego okazji, gdyż zachowuje historię wszystkich poprzednich commitów.

Czy jest coś, w czym merge ma przewagę nad rebase?

Główna przewaga merge to brak operacji, które zmieniają historię gałęzi. Dzięki temu, po scaleniu nie jest wymagane użycie force push. Rebase niestety nie jest tak łaskawe dla naszej gałęzi i wymaga jej całkowitego nadpisania. Bezpośrednią konsekwencją tego faktu jest brak możliwości pracy wielu osób na feature.

Jakie są z tego ogólne wnioski?

Ogólną zasadą jest częste używanie rebase na naszych prywatnych gałęziach. Pozwala to na scalanie zmian z master od razu jak tylko się pojawią, co minimalizuje konflikty.

Merge używamy do łączenia gałęzi współdzielonych przez wielu programistów. Zwykle dotyczy to długo budowanych i dużych zmian, dla których ciągłe nadpisywanie historii gałęzi było by niepraktyczne.

Leave A Comment