Git w praktyce

Od zawsze uważałem że najlepszą rzeczą jaką możemy zrobić żeby przyswoić wiedzę to zacząć jej używać w praktyce. W poście Podstawy GITa. poznaliśmy podstawowe pojęcia i komendy Gita. Dziś przejdziemy od słów do czynów i użyjemy systemu kontroli wersji Git do pracy nad bardzo prostą stroną internetową.

Zanim zaczniemy pracę z Gitem musimy go zainstalować. Klient Gita to po prostu program, który ściągamy ze strony: https://git-scm.com/download/win. Instalacja jest prosta i polega głównie na klikaniu “Next”.

Po zainstalowaniu klienta uruchamiamy program o nazwie Git bash. Otworzy nam się czarne okno (linia poleceń), jest to program konsolowy, czyli nie będziemy w nim klikać myszką a jedynie pisać na klawiaturze.

Git ma wiele dostępnych komend. Możemy wyświetlić podstawowe komendy wpisując “git” i naciskając Enter.

bash

Żeby zobaczyć pełną listę komend musimy (według opisu na dole) wpisać “git help -a” i nacisnąć Enter.

W tym poście stworzymy projekt prostej strony internetowej. Będzie składał się tylko z pliku index.html. Na początku założymy Repozytorium projektu. Potem dodamy do niego plik. Następnie w pliku zakodujemy prostą stronę z kolorowym tłem. Po czym stworzymy nowy Branch (dla nowej funkcjonalności) i zobaczymy, jak przełączać się pomiędzy nimi. Na koniec Zmergujemy się do głównego Brancha kończąc tym samym pracę nad nową funkcjonalnością.

Repozytorium

W konsoli programu Git bash wpisujemy komendę “mkdir C:\\DrogaProgramisty” i naciskamy Enter. Zostanie utworzony nowy folder na dysku C. Następnie przechodzimy do tego nowo utworzonego folderu: “cd C:\\DrogaProgramisty” (Enter).

Każde polecenie musimy zatwierdzić klawiszem Enter. Od tej pory przyjmujemy, że zawsze go naciskamy, ale ja już nie będę o tym pisał.

Aby założyć Repozytorium Gita używamy komendy “git init ProjektKolorowaStrona”. Polecenie utworzyło nowy folder o nazwie ProjektKolorowaStrona. Przechodzimy teraz do niego: “cd ProjektKolorowaStrona”.

bash init

Znajdujemy się w Repozytorium naszego projektu. Możemy zauważyć że konsola Git bash wyświetla kolorem zółtym nazwę folderu, w którym jesteśmy i obok w nawiasie kolorem niebieskim nazwę Brancha, na którym się znajdujemy. Dzięki temu zawsze wiemy na jakim Branchu pracujemy.

Przy zakładaniu nowego Repozytorium automatycznie zostanie założony Branch o nazwie master. Jest to główny Branch i wszystkie kolejne “rozgałęzia się” przeważnie od niego.

Po wpisaniu komendy “explorer .” (z kropką na końcu) zostanie uruchomione okienko z naszym folderem. Jest tam ukryty folder “.git” gdzie znajdują się pliki Gita, które umożliwiają nam śledzenie zniam na naszych plikach.

Jeżeli nie widzisz tego folderu, to znaczy że Twój system Windows nie pokazuje plików i folderów ukrytych. Można to zmieniać w ustawieniach systemu.

Dodawanie plików

Git służy do śledzenia zmian w plikach. Aby podejrzeć zmiany które wprowadziliśmy używamy komendy “git status”. Na razie nie mamy żadnych plików, także wyświetlona zostaje informacja o braku zmian.

Stwórzmy więc plik index.html. Możemy to zrobić wpisując polecenie “touch index.html”.

Zobaczmy teraz co wyświetla nam komenda “git status”.

bash status

Git wykrył nowy plik w naszym Repozytorium. Jest on zaznaczony na czerwono i znajduje się w sekcji Untracked files. To znaczy, że jeszcze nie śledzimy w nim zmian.

Nie zawsze chcemy śledzić zmiany we wszystkich plikach. Często mamy pliki pomocnicze, mało ważne, które możemy (i dla przejrzystości nawet powinniśmy) ignorować. Służy do tego komenda “git ignore <plik>”.

Dodajmy nasz nowy plik do śledzenia. Wpisujemy “git add index.html”. W tym momencie mówimy Gitowi, że interesują nas zmiany w tym pliku. Wpiszmy ponownie komendę “git status”. Widzimy, że nasz plik jest teraz w sekcji Changes to be commited i świeci się na zielono. Także jest git 🙂

bash add

Jeżeli mamy dużo plików, możemy dodać je wszystkie wpisujac “git add .” (z kropką na końcu).

Magia śledzenia zmian

Teraz przekonajmy się, o co tak naprawdę chodzi w tym śledzeniu zmian. Otwórzmy plik index.html w ulubionym edytorze tekstowym. Ja używam programu Notepad++ (https://notepad-plus-plus.org/) ale może być zwykły notatnik systemu Windows. Plik jest pusty. Wpiszmy tam słowo “test” i zapiszmy zmiany (Plik > Zapisz albo Ctrl+S). Wracamy do konsoli Git bash i wpisujemy “git status”.

Nasz plik index.html jest wyświetlany w dwóch sekcjach: Changes to be committed oraz Changes not staged for commit. O co chodzi? Otóż Git pamięta, że dodaliśmy plik index.html do śledzenia zmian. Ale w chwili dodawania był on pusty i taka informacja została “zapamiętana” przez Git. Teraz plik zawiera zmiany w stosunku do poprzedniej (zapamiętanej) wersji.

Możemy podejrzeć te zmiany wpisując “git diff”. Widzimy dziwne napisy. Jest to specjalny format, dzięki któremu Git wie, w którym pliku, w której linijce i jakie zmiany zostały wprowadzone.

bash diff

Aby dodać te zmiany do sekcji zielonej (czyli tej która będzie Committowana – zapisana w historii) wpisujemy ponownie “git add index.html”. Po dodaniu zmian i wpisaniu “git status” widzimy znowu tylko jedną, zieloną, sekcję.

Zauważ, że Git sam podpowiada Ci jakie dostępne opcje mogą być użyteczne i w tym właśnie dodanie zmian (“git add <file>”) lub ich wycofanie (“git checkout — <file>”).

Wpiszmy więc coś sensownego do pliku index.html. Stwórzmy stronę HTML. Teraz (po zapisaniu zmian w pliku) możemy otworzyć index.html w przeglądarce internetowej (czyli klikamy na plik 2x). Widzimy stronę z żółtym tłem. Możemy wpisać “git status” i “git diff” aby zaobserwować, jakie dokładnie zmiany zostały wprowadzone.

strona

Committowanie, czyli tworzenie historii zmian

Gdy już stworzyliśmy naszą stronę, możemy dodać tę wersję do historii. Czyli utrwalamy wszystkie pliki (te śledzone, w zielonej sekcji) w takiej postaci w jakiej są. W internecie możecie spotkać się z określeniem Snapshot, czyli takie “zamrożenie” wszystkich plików i tego co w nich jest.

Służy do tego komenda “git commit -m ‘Nowa strona z fajnym kolorem'”. Zauważ, że podajemy treść Commita. Jest bardzo ważne, aby opis tego co zrobiliśmy był dość szczegółowy żebyśmy za parę miesięcy wiedzieli co (i dlaczego) dodaliśmy.

Ważne aby sprawdzić za pomocą komendy “git status” czy wszystkie zmiany zostały dodane do Commita. Jeżeli o czymś zapomnieliśmy, będzie na czerwono.

Brawo! Właśnie stworzyliśmy pierwszy Commit w projekcie. Git zapamiętał wersje wszystkich śledzonych plików. Nadał im odpowiedni opis oraz swój wewnętrzny numer (pozwoli on nam przełączać się pomiędzy nowszymi i starszymi wersjami projektu).

bash commit

Przy okazji dowiadujemy się (z wyświetlonych informacji) ile plików się zmieniło, ile linii kodu zostało dodanych a ile usuniętych.

Naszą historię możemy zobaczyć wpisując “git log”. Widzimy informacje o autorze zmian oraz dacie. Wyświetlony jest też wpisany przez nas opis. Dlatego bardzo ważne jest aby dobrze oddawał wprowadzone zmiany.

bash log

Zmieńmy teraz napis w naszej stronie. Po zapisaniu zmian w pliku (Ctrl+S) komenda “git status” pokazuje, że nasz plik się zmienił. Super, to już wiemy. Komenda “git diff” pokazuje szczegóły tych zmian.

bash diff 2

Zauważ, że nasza zmiana napisu spowodowała tak naprawdę 2 zmiany. Po pierwsze usuwamy starą linijkę z tekstem “Kolorowa strona” i dodajemy nową linijkę z tekstem “Kolorowa strona z fajnym kolorem.”. Tak właśnie Git śledzi zmiany. Zmiana w danej linii kodu, to tak naprawdę zastąpienie jej inną linią kodu.

Committujemy nasze zmiany: “git add index.html”, “git status” (wszystko na zielono?!), “git commit -m ‘Nowy napis o kolorze'”.

Musimy pamiętać o dodaniu naszych zmian do Commita (zielonej sekcji). Dlatego komenda “git status” jest wskazana przed Committem.

bash commit 2

Komenda “git log” pokazuje już dwa wpisy historii zmian Repozytorium naszego projektu. Tak właśnie rozwijamy nasz projekt dodająć i śledząc wprowadzane zmiany.

Branchowanie czyli rozgałęzianie historii zmian

Branch to gałęź w naszym Repozytorium. Pierwszy Commit w historii to tak zwany Root (korzeń drzewa). Kolejne Commity sprawiają, że nasza gałęź rośnie. Repozytorium na chwilę obecną przedstawia się następująco:

SourceTree Repo

Drzewo Repozytorium (korzeń jest na dole, nowy Commit na górze)

Załóżmy, że wpadliśmy na pomysł że zmienimy kolor strony (plus jakieś inne zmiany, które dla lepszej czytelności pomijamy). Dobra praktyka pracy z Gitem nakazuje, aby większe i długo trwające zmiany wprowadzać do projektu w osobnych Branchach.

Możemy podejrzeć jakie gałęzie mamy w naszym Repozytorium. Wpiszmy “git branch”. Widzimy, że jest tylko jedna gałęź o nazwie master. Na zielono pokazany jest aktualny Branch na którym pracujemy.

Stwórzmy więc nową gałęź. Używmy do tego komendy “git branch nowykolor”. W tym momencie stworzyliśmy nowy Branch naszego kodu (o nazwie nowykolor), który zawiera dokładnie te same dane (pliki i ich zawartośc) jaka obecnie jest w naszym ostatnim Commicie.

bash branch

Po wpisaniu “git branch” widzimy już dwie gałęzie. Ale ciągle zaznaczona na zielono (czyli aktualna) jest główna gałęź master. Aby przełączyć się na nową gałęź wpisujemy “git checkout nowykolor”. Widzimy, że przełączyliśmy się na Branch o nazwie nowykolor. Zmienił się też napis w nawiasie w konsoli Git bash. Komendy “git status” i “git log” zachowują się tak jak do tej pory. Log wyświetla informacje z 2 poprzednimi Committami.

bash checkout

Wprowadzamy do naszego pliku index.html nowy kolor strony. Po zapisaniu i odświeżeniu w przeglądarce widzimy ładny zielony kolor. Komendy “git status” i “git diff” poprawnie pokazują wprowadzone zmiany. Dodajemy je do historii: “git add index.html“, “git status”, “git commit -m ‘Kolor zmieniony na zielony. Napis zmieniony na lepszy napis.'”.

strona 2

Stworzyliśmy Commit ale teraz w nowym Branchu nowykolor (bo aktualnie na nim się znajdowaliśmy).

Niezależne Branche

Obecnie znajdujemy się na Branchu nowykolor. Wróćmy na chwilę do głównego Brancha master. Wpisujemy “git checkout master”. W przeglądarce po odświeżeniu strony widzimy, że wróciliśmy znowu do starej wersji z żółtym kolorem. Co się stało? Otóż Git pamięta dokładnie na jakiej wersji skończyliśmy pracę w Branchu master. W tamtym momencie (2 Commity) zrobiliśmy nowy Branch i trzeci Commit dodaliśmy już na Branchu nowykolor. Nie jest on widoczny w głównym Branchu.

Każdy z Branchy jest niezależny od innych. Git przełączając się pomiędzy nimi, sam zmienia zawartość plików. Potrafi nawet tworzyć / usuwać pliki w zależności od tego, co robiliśmy w innych Branchach. Możesz się o tym przekonać wpisująć “git log”. Wyświetlone są tylko 2 Commity.

Dla chętnych: w Branchu master dodaj nowy plik, dodaj go do Commita a następnie przelącz się na Branch nowykolor. Zauważ że ten nowy plik zniknął 🙂

Obecnie drzewo naszego Repozytorium wygląda tak:

st 2

Drzewo Repozytorium. Branch master jest na drugim Commicie. Branch nowykolor jest na trzecim Commicie.

Możesz się trochę pobawić. Wpisuj na zmianę “git checkout master” oraz “git checkout nowykolor” i odświeżaj stronę w przeglądarce 🙂

Mergowanie czyli łączenie Branchy

Gdy już wprowadziliśmy wymagane zmiany w pobocznym Branchu przychodzi czas, aby włączyć je do Brancha głównego. Służy do tego komenda “git merge”.

Aby Zmergować dwa Branche przechodzimy na nasz główny Branch (ten do którego chcemy wrzucić zmiany zrobione w innym) używając komendy “git checkout master”.

Następnie wpisujemy “git merge nowykolor”. W naszym przypadku zmiany były na tyle proste, że Git wykonał tak zwany fast-forward. Czyli uaktualnił swoje wskaźniki i opisy i wskazuje na ten sam Commit co Branch nowykolor. W przypadku gdy fast-forward nie jest możliwy, Git dodałby zmiany jako tak zwany merge commit. Czyli w historii zmian “git log” pokazałby nie 3 (tak jak obecnie) a 4 Committy.

bash merge

Drzewo Repozytorium pokazuje, że oba Branche znajdują się na tym samym Commicie.

st 3

Drzewo Repozytorium. Oba Branche znajdują się na tym samym Commicie. Czyli posiadają dokładnie ten sam kod.

Po Zmergowaniu zmian do głównego Brancha i zakończeniu prac na Branchu pobocznym dobrze jest go usunąć. Robimy to za pomocą komendy “git branch -d nowykolor”. Dzięki temu historia zmian w naszym Repozytorium jest przejrzysta i czytelna.

Konflikty: czasami podczas Mergowania pojawiają się Konflikty. Dzieje się tak dlatego, że zmiany w obu Branchach były wykonywane na tym samym pliku i w tych samych linijkach. Git nie wie wtedy, która wersja jest ważniejsza. To programista musi o tym zdecydować.

O tym jak rozwiązywać Konflikty w bardziej skomplikowanych Mergach, powiemy sobie innym razem.

Dobrze jest myśleć o śledzeniu zmian w Git jako o przesuwaniu wskaźników Branchy pomiędzy różnymi Commitami. Możemy całkiem dowolnie je przesuwać i wracać do innych wersji.

Na koniec

I to tyle na dziś. Całkiem dużo wiedzy i komend. Wiem, że na początku Git wydaje się skomplikowany. Pamiętam jak sam się go uczyłem. Warto jednak opanować przynajmniej te najbardziej potrzebne komendy, aby czerpać dużą przyjemność z pracy nad kodem.

Poniżej spisałem listę wszystkich użytych komend wraz z wyjaśnieniem. Taka bonusowa ściągawka 🙂

Komendy systemu Windows:

  • “mkdir <folder>” : tworzymy nowy folder o podanej nazwie
  • “cd <folder>” : przechodzimy do folderu o podanej nazwie
  • “explorer .” : otwieramy Windows Explorer z obecnym folderze
  • “touch <plik>” : tworzymy nowy plik

Komendy Gita:

  • “git” : wyświetlamy listę najpopularniejszych opcji
  • “git help -a” : wyświetlamy listę wszystkich dostępnych opcji
  • “git init <nazwa Repozytorium>” : tworzmy nowy folder i Repozytorium o podanej nazwie
  • “git status” : wyświetlamy informacje o śledzonych zmianach i plikach które się zmieniły
  • “git ignore <plik>” : dodajemy plik do ingorowanych, Git nie będzie śledził zmian na tym pliku
  • “git add <plik>” : dodajemy plik (zmiany w pliku) do następnego Commita
  • “git add .” : dodajemy wszystkie pliki (zmiany w nich) do następnego Commita
  • “git diff” : wyświetlamy szczegóły wprowadzanych właśnie zmian
  • “git checkout — <plik>” : cofamy zmiany w danym pliku (wracamy do wersji tuż po poprzednim Commicie)
  • “git commit -m ‘<opis>'” : tworzymy Commit ze wszystkimi śledzonymi zmianami i oznaczamy go w historii Repozytorium (ale tylko te na zielono z komendy “git status”)
  • “git log” : wyświetlamy historię Repozytorium
  • “git branch” : wyświetlamy listę Branchy
  • “git branch <nazwa>” : tworzymy nowy Branch z tego na którym obecnie jesteśmy
  • “git branch -d <nazwa>” : usuwamy Branch o podanej nazwie
  • “git checkout <nazwa>” : przechodzimy na Branch o podanej nazwie, od teraz wszystkie zmiany dotyczą właśnie tego Brancha
  • “git merge <nazwa>” : do obecnego Brancha na którym jesteśmy Mergujemy zmiany z innego Brancha o podanej nazwie

I na koniec screen naszego Repozytorium z programu Source Tree.

st4

Jest to graficzny edytor, który bardzo ułatwia pracę z Gitem. Jeżeli konsola programu Git bash jest jeszcze zbyt obca, śmiało możesz używać tego graficznego edytora 🙂

2 replies
  1. Samu
    Samu says:

    Była taka opcja w gicie by móc zamrażać pliki, gdzieś to kiedyś widziałem, a teraz by mi się to przydało i nie mogę znaleźć.
    Chodzi o pliki konfiguracyjne, które chcemy by były w gicie, ale by git nie pozwalał na zmiany w takich plikach, bo u każdego konfiguracja może być inna i nie chcę, by ktoś nadgrywał te pliki w repozytorium gita. Według mnie to jedna z podstawowych opcji, czemu tego nie ma w podstawach, czy nikt tego nie używa?

    Reply
    • creyn
      creyn says:

      Dzięki za ciekawy komentarz.

      Są różne podejścia do trzymania konfiguracji w repozytorium. Osobiście sugerowałbym trzymanie tylko przykładowej konfiguracji (np. config.sample.txt) a faktyczną konfigurację trzymać już lokalnie na danym środowisku (czy to PROD czy DEV) i ustawiać ją przy uruchamianiu. Ale to pomysł na osobny wpis.

      Co do funkcjonalności zamrażania w git to jest to bardziej skomplikowany temat. Jedyną opcją jaką widzę to zastosowanie “pre-receive hook”. Czyli kawałek skryptu który uruchamia się po stronie serwera (żeby nikt nie mógł sobie lokalnie go zmienić). Skrypt sprawdza czy przypadkiem ktoś nie zmienił danego pliku i nie pozwala na to. Programista dostaje ładną informację, że tego i tego pliku nie można zmieniać.

      Inne rozwiązania zamrażania (np. git update-index) działają lokalnie dla danego programisty. Wszyscy w zespole musieliby się do tego stosować i obiecać że nie będą nic “grzebać”. Dlatego jedynym rozwiązaniem jakie widzę to pre-receive hook po stronie serwera. Plus odpowiednie uprawnienia, żeby nikt poza Tobą nie mógł edytować hooka.

      Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *