Git branch – czym są gałęzie w systemi kontroli wersji?

Dawno nie było w kursie o samym Gicie – na samym początku pokazałem Ci podstawy Gitach byś potrafił wysyłać swoje zmiany na zdalne repozytorium. Jednak prawdopodobnie Twoja wiedza na temat Gita nie jest wystarczająca do pracy w zespole nad wspólnym projektem, a to jest główna siła tego narzędzia.

W takim razie w tym tygodniu postaram się Cię nauczyć pracować z Gitem przy użyciu wielu gałęzi czyli tak jak dzieje się to codziennie w każdej firmie programistycznej.

Czym jest branch?

Branch to nic innego jak gałąź – czyli taka odnoga naszego projektu, utworzona w danym czasie. Coś takiego jak kopia – może żyć swoim życiem i w każdej chwili może być dołączona do głównej gałęzi.

W końcu miałeś już do czynienia w Gicie z jedną gałęzią – a tą gałęzią jest właśnie master czyli główna gałąź repozytorium.

Branch może zostać utworzony tak naprawdę na podstawie każdej z innych gałęzi, lecz zazwyczaj się to robi na podstawie głównej gałęzi – master.

Po co te całe gałęzie?

Gałezię pozwalają w bardzo w prosty sposób pracować wielu osobom jednocześnie nad danym projektem. Przypuśćmy, że mamy duży projekt, szykuje się nowa wersja produktu – około 12 feature’ów, 5 programistów.

Dzięki branchom wszyscy programiści mogą pracować równolegle nie wchodząc sobie wcale w paradę – jak by to wyglądało?

Każdy programista na początek wziąłby jedno zadanie – jedna dodatkowa funkcjonalność i dla niej utworzyłem osobny branch odłączając się od gałęzi master. Po ukończeniu swojego zadania mógłby dołączyć swój branch do mastera i pracować nad kolejnym – łączeniem gałęzi zajmiemy się w kolejnej lekcji. Teraz skupmy się na branchach.

Jakieś komendy?

W tej lekcji będzie używać głównie dwóch komend:

Sprawdzenie dostępnych gałęzi w repozytorium:

git branch

Utworzenie nowego brancha

git branch <nazwa-brancha>

Przełączenie się na gałąź

git checkout <nazwa-brancha>

Przełączenie się na gałąź i utworzenie jeśli jeszcze nie istniała:

git checkout -b <nazwa-brancha>

Przyda nam się jeszcze jedna – do sprawdzenia historii commitów danego brancha

git log

I to tyle – nie musisz ich już teraz zapamiętywać, będę je wykorzystywał w trakcie dalszej części lekcji. Bez problemu wejdą Ci szybko do głowy. 😉

Init project

Na początku musimy stworzyć w ogóle jakieś repozytorium – przypuśćmy, że stworzymy naprawdę prosty projekt – stwórz zwykły projekt Javy oraz zainicjalizuj git repository komendą:

git init .

Gdy mamy już repozytorium możemy dodać do niego plik .gitignore, który definiuje pliki/foldery, które mają nie być brane pod uwagę podczas śledzenia zmian. Krótko mówiąc GIT się nimi w ogóle nie interesuje, a dodatkowo nie będą one wysyłane na zewnętrzne repozytorium.

Ignorowane są zazwyczaj zewnętrzne biblioteki, pliki wynikowe lub pliki utworzone przez IDE – nie ma co zaśmiecać głównego repozytorium rzeczami, które każdy sam może wygenerować w swoim środowisku.

Wystarczy utworzyć plik .gitignore w katalogu projektu i zapisać tam takie trzy linie:

/target
/out
/.idea

Dzięki temu folery target out nie będą brane pod uwagę – są to katalogi wynikowe oraz .idea, który przechowuje informację o projekcie w IntelliJ Idea. Mając taki plik zapisujemy go i robimy klasycznie init commita.

Czyli musimy dodać wszystkie pliki i stworzyć z nich commita

git add *
git commit -m "Init commit"

Jeśli chcesz może również dodać swojego zdalne repozytorium, jednak ja tego nie będę póki co robił – zrobię to na koniec lekcji, abyś mógł zobaczyć mój kod.

CreateUser Feature

Pierwszym naszym zadaniem jest wykonanie funkcjonalności createUser czyli możliwości stworzenia Usera w klasie Main – chcę, żeby przykład był naprawdę prosty. 😉

Na początku wylistujmy sobie dostępne branche:

git branch

I jak widać istnieje tylko master:

* master

Stwórzmy, więc nasz pierwszy branch – create-user

git branch create-user

I tym razem po wylistowaniu otrzymamy trochę dłuższą listę:

  create-user
* master

Widzisz, że gwiazdka jest tylko przy masterze – oznacza to, że aktualnie jesteśmy na gałęzi master!

Zmieńmy, więc branch na create-user

git checkout create-user

I powinniśmy otrzymać:

Switched to branch 'create-user'

I możemy rozpocząć prace na naszym featurem – stwórzmy prostą klasę User:

package pl.maniaq;

public class User {
    private String name;
    private String lastname;
    private Integer age;

    public User(String name, String lastname, Integer age) {
        this.name = name;
        this.lastname = lastname;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", lastname='" + lastname + '\'' +
                ", age=" + age +
                '}';
    }
}

Zakomitujmy zmiany:

git add *
git commit -m "Create User class"

Dodajmy teraz w klasie Main, możliwość wczytania danych od użytkownika i utworzenia Usera – wykorzystamy po prostu dobrze znany Scanner:

package pl.maniaq;
import java.util.Scanner;

public class Main {

    Scanner scanner = new Scanner(System.in);

    public void createUser() {
        String name, lastname;
        Integer age;

        System.out.println("Type a name: ");
        name = scanner.next();

        System.out.println("Type a lastname: ");
        lastname = scanner.next();

        System.out.println("Type your age: ");
        age = scanner.nextInt();

        User user = new User(name, lastname, age);
        System.out.println("Utworzono Usera: " + user.toString());
    }

    public static void main(String[] args) {
  // write your code here
    }
}

I ponownie zacommitujmy zmiany na naszej gałęzi:

git add *
git commit -m "Implement create user method in main class"

Ale jak widać się pomyliłem – zapomniałem wywołać metody w metodzie main, teraz Main wygląda tak:

package pl.maniaq;
import java.util.Scanner;

public class Main {

    static Scanner scanner = new Scanner(System.in);

    public static void createUser() {
        String name, lastname;
        Integer age;

        System.out.println("Type a name: ");
        name = scanner.next();

        System.out.println("Type a lastname: ");
        lastname = scanner.next();

        System.out.println("Type your age: ");
        age = scanner.nextInt();

        User user = new User(name, lastname, age);
        System.out.println("Utworzono Usera: " + user.toString());
    }

    public static void main(String[] args) {
        createUser();
    }
}

I ponownie musimy zacommitować zmiany:

git add *
git commit -m "Call createUser function in main method"

I teraz możemy wyświetlić sobie całą historię zmian na naszej gałęzi:

git log

I wtedy widzimy wszystkie nasze commity:

commit 2720852d2eb7afde997c907d990a8b4a8b14f3b8
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:34:12 2018 +0200

    Call createUser function in main method

commit ed4163a50658c78d7339a1b93fc05cc265ce2e93
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:32:00 2018 +0200

    Implement create user method in main class

commit 0514884fc4dd0d355c7e72da54655fa3b2e76e08
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:28:39 2018 +0200

    Create User class

commit e09ee4d2f7d3fc13bad8094b42d2cae758c08ad0
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:23:57 2018 +0200

    Init commit

Calculatator Feature

Kolejnym naszym zadaniem jest stworzneie klasy odpowiedzialnej za podstawowe operacje matematyczne – prosty kalkulator.

W takim razie wracamy do gałęzi głównej, ponieważ od niej będziemy tworzyć nową gałąź

git checkout master

Oraz tworzymy nową gałąź feature/calculator – dobrze jest dodawać przedrostek np. feature/hotfix/release/bugfix, aby wiedzieć co jest celem tego brancha

git checkout -b feature/calculator

Tym razem użyliśmy komendy checkout z parametrem -b, aby utworzyć branch i automatycznie przejść do niego.

I jak widać automatycznie zostaliśmy przeniesieni do nowego brancha:

Switched to a new branch 'feature/calculator'

I mam teraz takie branche:

  create-user
* feature/calculator
  master

A nasza historia commitów wygląda aktualnie tak: (git log)

commit e09ee4d2f7d3fc13bad8094b42d2cae758c08ad0
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:23:57 2018 +0200

    Init commit

Dlaczego tak? Ponieważ utworzyliśmy gałąź od głównej gałęzi, gdzie był wykonany tylko init commit – zmiany na branchu create-user w ogóle nas nie dotyczą, dopóki ich nie dołączymy.

W takim razie stwórzmy sobie prostą klasę obsługującą podstawowe operacje matematyczne:

package pl.maniaq;

public class Calculator {
    
    public static Integer add(Integer numberOne, Integer numberTwo) {
        return numberOne + numberTwo;
    }


    public static Integer subtract(Integer numberOne, Integer numberTwo) {
        return numberOne - numberTwo;
    }


    public static Integer multiply(Integer numberOne, Integer numberTwo) {
        return numberOne * numberTwo;
    }


    public static Float divide(Integer numberOne, Integer numberTwo) {
        return numberOne / (float) numberTwo;
    }
}

Zacommitujmy oczywiście zmiany:

git add *
git commit -m "Create calculator class" -m "Class contains methods: add/subtract/multiply/divide"

I teraz użyjmy naszej klasy w Main – dwie liczb od użytkownika i wynik wszystkie operacji na ekran – nic trudnego.

package pl.maniaq;

import java.util.Scanner;

public class Main {

    static Scanner scanner = new Scanner(System.in);

    public static void calculate() {
        Integer x, y;

        System.out.println("Type first number: ");
        x = scanner.nextInt();

        System.out.println("Type second number: ");
        y = scanner.nextInt();

        System.out.println("Sum: " + Calculator.add(x, y));
        System.out.println("Subtract: " + Calculator.subtract(x, y));
        System.out.println("Multiply: " + Calculator.multiply(x, y));
        System.out.println("Divide: " + Calculator.divide(x, y));
    }


    public static void main(String[] args) {
        calculate();
    }

}

I oczywiście zacommitujmy naszą zmianę:

git add *
git commit -m "Implement method calculate in main class" -m "Calculate method use Calculator class to calculating basic math operations"

I zróbmy teraz git log:

commit e86c8d90aa05187f7105f81a62c507a16851842f
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:47:36 2018 +0200

    Implement method calculate in main class
    
    Calculate method use Calculator class to calculating basic math operations

commit 4431d049ae8dfeadb5446200d16d1d7c45a5d5b2
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:43:25 2018 +0200

    Create calculator class
    
    Class contains methods: add/substract/multiply/divide

commit e09ee4d2f7d3fc13bad8094b42d2cae758c08ad0
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:23:57 2018 +0200

    Init commit

I jak widać nasze zmiany są widoczne na naszym branchu w historii commitów.

Na koniec

Na koniec wróćmy, więc do głównej gałęzi:

git checkout master

Oraz sprawdźmy ponownie historię mastera:

git log

I otrzymamy:

commit e09ee4d2f7d3fc13bad8094b42d2cae758c08ad0
Author: klimson <klimson@gitlab.com>
Date:   Tue Oct 2 19:23:57 2018 +0200

    Init commit

I jak widać żadna zmiana na branchu nie wywołała zmian na masterze – czyli praca równoległa wielu programistów jest możliwa.

Jednak co teraz z tymi gałęziami?

Trzeba będzie je dołączyć do głównej gałęzi – jednak tym zajmiemy się już w następnej lekcji kursu!

Aby wypchnąć wszystkie swoje branche na zdalne repozytorium musisz użyć komendy:

git push origin --all

Dzięki temu zostaną wysłane wszystkie dostępne branche. 😉

Jeśli chcesz zobaczyć moje repozytorium utworzone w tej lekcji zerknij tutaj – możesz zobaczyć tam wszystkie commity oraz utworzone branche klikając po portalu GitHub.

 

Kamil Klimek

Od 2016 jestem programistą Java. Przez pierwsze 4 lata pracowałem jako Full Stack Java Developer. Później postanowiłem postawić nacisk na Javę, żeby jeszcze lepiej ją poznać.

Subscribe
Powiadom o
guest
0 komentarzy
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x