Git – krótka historia pewnego brancha


Powiedzmy że przerabiam kurs, a postępy commituję i wrzucam z gałęzi master na Github.  Nachodzi mnie jednak zamysł aby móc coś podłubać w kodzie, który już mam – zboczyć z kursu.  Rodzą się jednak komplikacje, bo kurs jest kursem i chcę mieć czysty materiał, z ładnie zachowanym porządkiem przerabianych rzeczy. Generalnie raczej zasada jest taka, że na serwer wysyła się zawsze działającą wersję, więc jak coś mi się uda zrobić z sensem, to wtedy powinienem dołączyć do głównego projektu i wypchnąć na serwer. Zaś robić parę wersji tego samego projektu trzymając po różnych katalogach i przeładowywać do IDE… bez sensu jak już i tak korzystam z Git-a.

Taki mniej więcej może być przykładowy scenariusz, że nawet jeżeli jesteś dev-wannabe, uczysz się sam, to dodatkowy branch się przyda. Daje on opcję eksperymentowania z kodem na bocznej gałęzi, przy jednoczesnym programowaniu na master i wypychaniu tylko z tego brancha – feel free!

Nowa gałąź

Utworzenie nowej gałęzi i przełączenie się na nią:

git branch branch-name
git checkout branch-name

lub utworzenie i przełączenie w jednej linijce:

git checkout -b branch-name

W tym momencie na nowym branchu znajduje się to samo co na branchu, na którym byłem kiedy go tworzyłem. Jeżeli więc, nie tworzyłem wcześniej żadnych gałęzi, to mam kopię z master i jest to punkt wyjścia do dalszej pracy, niezależnej od master.

Po jakimś czasie przychodzi moment aby połaczyć – zmergować, moją boczną gałąź z gałęzią master. Narobiłem tam jednak ileś commitów o różnych, mniej lub bardziej szczęśliwych nazwach i nie chcę tak od razu łączyć jej z master, bo one wszystkie będą zbędnie widoczne i kiepsko pasujące do historii głównej gałęzi. Chcę mieć przykładowo tylko jeden commit na bocznej gałęzi, odpowiednio go nazwać i żeby on był widoczny w historii na master.

Rebase, czyli robienie zgniotka

Aby zgnieść określoną ilość rewizji, na bocznej gałęzi od master, w jeden wynikowy commit:

git rebase -i HEAD~3

Powinno się pojawić interaktywne okno wyboru w domyślnym edytorze tekstu, na Debianie mam w Nano. Liczba po HEAD~ oznacza ilość commitów od najnowszego jakie mają być zgniecione w jeden.

Następnie w linijkach z rewizjami Feature 3Feature 2 zamiast pick wpisuję squash lub fixup, bądź ich literkowy skrót.
Zapisuję – ctrl+o, zatwierdzam – enter, wychodzę – ctrl+x i można sprawdzić logi:

git log

Wyświetli się pełna lista rewizji wraz z ich log message, a z trójki zaznaczonych do zgniecenia commitów powinien zostać jeden wynikowy – Feature 1. Każda rewizja  ma swój log message, jeżeli wybrałem opcję fixup, to w jego logach zostało pominięte info o zgnieceniu, a jeżeli squash, to będzie widać jakie commity ma w brzuszku. Wygodniejszą alternatywą dla git log jest zapewniające jedno-liniowy wynik dla każdej rewizji:

git log --oneline

Jeżeli nie podoba się nazwa rewizji lub nie będzie pasować do historii na master to:

git commit --amend -m "Other-name"

Merge, czyli scalenie master z jej odgałęzią

Przełączam się na master, sprawdzam czy aby na pewno tam się znajduję i merguję ją z odgałęzieniem od niej, na którym był rebase:

git checkout master
git branch
git merge branch-name

Btw. Jeżeli były by jeszcze jakieś dodatkowe boczne gałęzie od tej bocznej do master, to proces wygląda podobnie, po prostu najpierw trzeba połączyć tą boczną z jeszcze bardziej boczną, a dopiero później boczną z master.

Achtung konflikt!

W najprostszym przypadku, Git ma dwa pliki z dwóch branchy, które pragnie połączyć w jeden i umieścić na master. Wyszedł jednak konflikt bo na tych samych liniach obu plików ma różną treść i nie wie co wybrać. Git słusznie nie nadpisze pliku o tej samej nazwie z głównej gałęzi, treścią z odgałęzi, bo nie wiadomo co jest prawidłowe. Generalnie nie ma problemu jak na odgałęzieniu tworzę nowe pliki ale jeżeli coś zmieniam w istniejących, to trzeba się liczyć z tego typu sytuacją.

Git w takim wypadku poinformuje podczas mergowania o jaki (wiadomo, może być ich więcej) plik chodzi i wklei do niego oznaczenie co jest na HEAD (aktualny branch – master), a co przyszło z odgałęzi i odseparowuje: “=======“.

<<<<<<< HEAD
int x = 5;
=======
int x = 10;
>>>>>>> branch-name

Trzeba edytować plik, usunąć znaczniki gita, wybrać prawidłową treść, następnie dodać plik do poczekalni:

git add .

Mergować jeszcze raz nie trzeba, więc tylko zatwierdzić nową rewizję:

git commit -m "Commit-name"

Ewentualnie wypchnąć ją na serwer:

git push

Ewentualnie dla porządku usunąć zmergowane z master odgałęzienie:

git branch -D branch-name

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *