System kontroli wersji Git był tematem dwóch niedawnych wpisów na moim blogu: No i Git! Kontrola wersji służy nie tylko programistom oraz Git w Eclipse. W tym odcinku chcę na jakiś czas zamknąć temat. Skoncentruję się na kwestii odgałęzień w kodzie (branches).
Git pozwala na przyjemną i efektywną pracę z branchami. Łatwo je tworzyć, scalać i usuwać. Wczoraj zabrałam się za tworzenie szkieletu mojej konkursowej aplikacji Szafbook i wykorzystałam to jako pretekst do poeksperymentowania z odgałęzieniami.
Ogólny zarys moich działań
- Utworzenie nowego brancha w konsoli.
- W ramach brancha: przygotowanie szkieletu aplikacji Spring Boot za pomocą serwisu https://start.spring.io/.
- Wcielenie zmian z nowego brancha do głównej linii kodu (konsola).
- Utworzenie brancha przez interfejs Eclipse.
- W ramach brancha: prace mające doprowadzić kod do stanu, w którym się kompiluje.
- Wcielenie zmian z nowego brancha do głównej linii kodu (Eclipse).
- Ustalenie, dlaczego nie było mi potrzebne słowo
rebase
.
Konsola
W oparciu o informacje w odpowiednim rozdziale podręcznika, tworzę nową gałąź (o nazwie bootinit):
1 |
$ git checkout -b bootinit |
Powyższe polecenie jest skrótem dla dwóch innych, z których pierwsze tworzy brancha, a drugie mnie do niego przenosi:
1 2 |
$ git branch bootinit $ git checkout bootinit |
Następnie wprowadzam swoje zmiany. W tym wypadku to wrzucenie szkieletu aplikacji webowej do katalogu projektowego oraz usunięcie niepotrzebnych mi już plików.
Po wprowadzeniu zmian polecenie git status
zwraca następującą informację):

Chcę śledzić wszystkie te zmiany i chcę je uwzględnić w kolejnym commicie, dlatego dodaję wszystko:
1 |
$ git add -A |
Alternatywnie mogłabym zaznaczyć poszczególne zmienione i dodane pliki poleceniem git add <plik>
, a usunięte pliki poleceniem git rm <plik>
.
Na tym etapie postanawiam wysłać swoje zmiany do repozytorium:
1 |
$ git commit -m "initial webapp template" |
Załóżmy, że moje prace w gałęzi bootinit osiągnęły taki poziom dojrzałości, że chcę scalić je z główną gałęzią kodu (master).
W tym celu muszę przejść do gałęzi, do której mam wrzucić zmiany i tam wywołać polecenie merge
.
1 2 |
$ git checkout master $ git merge bootinit |
Jeśli gałąź nie będzie mi już potrzebna, mogę ją usunąć:
1 |
$ git branch -d bootinit |
I już.
Eclipse
Teraz przerzucam się na pracę w środowisku Eclipse. Na początku importuję istniejący projekt z repozytorium Git.
W Eclipse narzędzia związane z kontrolą wersji znajdują się w menu kontekstowym projektu, w zakładce Team.

Tworzę nową gałąź korzystając z opcji wyświetlonej na powyższym obrazku: Team->Switch To->New Branch
Nazwa aktualnej gałęzi jest wyświetlana przy nazwie projektu.

Dalej wprowadzam swoje zmiany. Przed wszystkim chcę doprowadzić aplikację do stanu, w którym kompiluje się bez błędów (za pomocą Mavena) i zawiera chociaż jeden (bezsensowny na razie) test jednostkowy.
Jedna ze zmian to oznaczenie części plików w katalogu projektu jako ignorowanych – mam na myśli pliki stanowiące wynik kompilacji. W systemie kontroli wersji chcę trzymać tylko źródła. W menu mamy odpowiednią opcję Ignore, która jest powiązana ze zrozumiałym dla Gita plikiem .gitignore.
Praca w ramach jednej gałęzi została już umówiona w poprzednim wpisie. Załóżmy teraz, że wszystkie zmiany zostały wysłane do repozytorium, a prace w ramach nowej gałęzi eclipsebranchtest zostały zakończone.
Podobnie jak w przypadku pracy w konsoli, najpierw muszę przejść do gałęzi, do której chcę wcielić zmiany (w tym wypadku to master). Tam z menu Team wybieram opcję Merge. Pojawi się okienko przedstawione na poniższym obrazku.

No i to by było na tyle! Mogę jeszcze usunąć niepotrzebną już gałąź w Team->Advanced->Delete Branch.
Rebase
Spodziewałam się, że podczas zabawy z branchami dotrę do momentu, w którym potrzebne stanie się słówko rebase
, ale tak się nie stało. Nie pozostało mi nic innego jak RTFM. Oto, co ustaliłam (w wielkim skrócie):
Scalać można albo przy użyciu merge
, albo rebase
. W zależności od dokonanego wyboru, inaczej będzie wyglądała historia zmian w projekcie. Po merge
historia będzie dokładnie odwzorowywała to, co się działo – wszystkie rozgałęzienia i powroty. Dla odmiany rebase
pozwala nieco przepisać historię, w taki sposób, że – mimo pracy w odgałęzieniach – wygląda ona na liniową. Nie jest to prawda historyczna, ale ta forma może okazać się znacznie bardziej czytelna.
[edit: popełniłam jeszcze jeden wpis na temat rebase]
PS.
Wrócę z tematem Gita, jak dorobię się pierwszego poważnego konfliktu w kodzie.