Git tutorial | stash, rebase, commit, merge, checkout, push i clone

Git tutorial

Tutorial Git wprowadzi Cię krok po kroku w tajniki systemów kontroli wersji. Kurs oparty jest o przykłady z objaśnieniami konkretnych zagadnień. Z powodzeniem można go potraktować jako monolit i przeczytać od deski do deski, ale sprawdzi się również jako ściąga z wybranych funkcjonalności Git.

Git – wprowadzenie

Z tego materiału dowiesz się:

  • Jakie istnieją rodzaje systemów kontroli wersji?
  • Czym jest Git?
  • Jakie są stany plików w Gicie?
  • Jak skonfigurować Git’a?
  • Jakie możliwości daje Ci Git?
  • Czym jest Git-flow?

Systemy kontroli wersji kodu źródłowego

Systemy kontroli wersji odpowiedzialne są za śledzenie wszystkich zmian dokonywanych w plikach. Za ich pomocą można podejrzeć wcześniej dokonane zmiany oraz, w razie potrzeby, powrócić do starszej wersji pliku. Dzięki nim można również sprawdzić kto i kiedy dokonał tych zmian.

Kiedy jesteś w większym projekcie, dość dynamicznie pojawia się dużo zmian. Zdarzają się sytuacje, w których wprowadzona linia kodu jest błędna lub też chcesz dopytać twórcę, dlaczego coś jest tak, a nie inaczej. Średnim pomysłem byłoby chodzenie od biurka do biurka z pytaniem: Czy to Ty wprowadziłeś tę zmianę? O wiele łatwiejsze jest sprawdzenie w systemie kontroli wersji, kto i kiedy dokonał zmiany. Dzięki niemu szybko będziesz mógł określić twórcę danego kodu.

Zanim opowiem Ci o najpopularniejszym obecnie systemie kontroli wersji, jakim jest Git, chcę przedstawić Ci jeszcze inne rozwiązania. Aby lepiej zrozumieć Git’a warto poznać jego prostsze alternatywy 👨🏼‍🏫

Lokalne systemy kontroli wersji

Najprostszą formą lokalnego systemu kontroli wersji jest metoda polegająca na przekopiowaniu wszystkich plików do osobnego katalogu. Nowo powstały katalog można też, oznaczyć datą powstania lub numerem wersji.

Takie podejście, z racji swojej prostoty, jest dosyć kuszące i jednocześnie wystarczające dla wielu podstawowych sytuacji. Jednak jego główną wadą jest brak odporności na błędy użytkownika. Przykładowo – wystarczy pomylić katalog, na którym się pracuje i można w ten sposób stracić całą swoją pracę.

W celu zabezpieczenia się przed tym dosyć szybko powstały proste systemy kontroli wersji oparte o bazę danych. W lokalnej bazie przechowywane były kolejne zmiany, które były dokonywane na wersjonowanych plikach. Dzięki temu można było już porównywać ze sobą zmiany z kolejnych wersji oraz, w razie czego, przywrócić stabilną wersję.

Jednym z najbardziej popularnych systemów tego typu jest RCS (Revision Control System).

Lokalny system kontroli wersji
Niestety lokalne systemy kontroli wersji mają jedną znaczącą wadę. Ogranicza je możliwość wykonywania zmian tylko do jednego komputera 💻 👎🏼

Scentralizowane systemy kontroli wersji

Scentralizowane systemy kontroli wersji CVCS (Centralized Version Control System) powstały w celu umożliwienia pracy na plikach, z więcej niż jednej maszyny 💻 💻

W tym celu zaprojektowano model, w którym jest jeden centralny serwer przechowujący wszystkie wersjonowane pliki oraz maszyny klienckie. Klienci łączą się do niego, w celu pobrania najnowszych zmian. Ten model jest już na tyle funkcjonalny, że jest wykorzystywany powszechnie do dziś.

Wielką zaletą tego rozwiązania jest możliwość zarządzania uprawnieniami z jednego miejsca. Dzięki temu można również łatwo zweryfikować zmiany wprowadzone przez każdego uczestnika procesu.

Natomiast główny problem systemów scentralizowanych związany jest z ich potencjalną awaryjnością. Wystarczy, że główny serwer będzie przez chwilę niedostępny, a żaden klient nie może pobrać najnowszych zmian oraz zapisać swojej pracy. W przypadku uszkodzenia dysku z przechowywanymi plikami tracona jest również cała historia projektu.

Najbardziej popularne systemy tej klasy to CVS i Subversion.

Scentralizowany system kontroli wersji

Rozproszone systemy kontroli wersji

Zdecydowanie bardziej rozwiniętą wersją, jeżeli mówimy o systemach kontroli wersji są rozproszone systemy kontroli wersji DVCS (Distributed Version Control System). Główna różnica polega na tym, że klienci nie pobierają tylko najnowszych zmian, a całe dostępne repozytorium. Dlatego w przypadku awarii głównego serwera wystarczy przekopiować pliki od jednego z klientów na nowy serwer i nie zostanie stracona historia projektu. W razie potrzeby klient też sam może służyć jako serwer główny dla innych klientów. Wygląda to trochę tak, że klienci dogadują się, który z nich będzie pełnił funkcję serwera i łączą się do niego.

Rozproszone systemy kontroli wersji

Ciekawostką jest również to, że wiele z systemów tej klasy potrafi współpracować jednocześnie z kilkoma różnymi serwerami zewnętrznymi. Daje to ogromne możliwości, jeżeli chodzi o stosowanie różnych modeli współpracy.

Najpopularniejsze systemy tego typu to: Git oraz Mercurial.

Git | Git tutorial

Obecnie Git jest najpopularniejszym rozproszonym systemem kontroli wersji.

Poznajmy Git’a trochę bliżej:

  • System został stworzony przez Linusa Torvalds jako narzędzie wspomagające rozwój jądra Linux.
  • Git oficjalnie został wydany w 2005 roku.
  • Obecnie jest rozwijany na zasadach wolnej licencji GNU GPL v2.

Praca na zmianach

Podstawową cechą odróżniającą Gita od innych podobnych narzędzi jest sposób przechowywania zmian w lokalnej bazie danych. Większość systemów (np. CVSSubversion) przechowuje informacje o nowej wersji jako różnicową listę zmian, jakie zaszły na plikach.
Git natomiast tworzy swego rodzaju migawkę (ang. snapshot) stanu repozytorium w danym momencie. W zapisanym w ten sposób obrazie repozytorium przechowane są informacje o wszystkich plikach, jakie są przechowywane w repozytorium. W celach optymalizacyjnych, jeżeli w danej wersji plik nie był zmieniany, przechowywana jest tylko referencja do jego najnowszej wersji.

Praca lokalnie

Większość operacji wykonywanych przy pomocy Gita nie wymaga połączenia do Internetu. Jest to ogromny krok w przód w porównaniu do innych systemów. Nie tylko przeglądanie historii wersji trwa wielokrotnie szybciej, ale np. do rozpoczęcia pracy z nowym plikiem nie trzeba już łączyć się do zdalnego serwera.
Dzięki temu, że prawie wszystko dzieje się offline, praca z systemem kontroli wersji już dużo szybsza. Dopiero na koniec pracy potrzebne jest połączenie internetowe, w celu wysłania swojej pracy na serwer lub pobrania najnowszych zmian.

Stany plików w Git

Żeby móc pracować z Gitem trzeba zrozumieć, w jakich stanach mogą znajdować się zarządzane przez system pliki. Git wprowadza trzy główne stany dla zmian: zmodyfikowany, śledzony oraz zatwierdzony.

  • Zmodyfikowany — plik był edytowany, ale zmiana o tym nie została jeszcze nigdzie zapisana.
  • Śledzony — zmodyfikowany plik został oznaczony do zatwierdzenia przy najbliższej operacji commit.
  • Zatwierdzony — dokonana zmiana została zapisana i utrwalona w lokalnej bazie danych.

Przesłanie zmian do zdalnego repozytorium jest już operacją opcjonalną.
Stany plików Git
Każdy stan wiąże się bezpośrednio z miejscem, w którym konkretna zmiana się znajduję:

  • Katalog roboczy — jest to odtworzony obraz wersji projektu. To właśnie zawartość tego katalogu jest modyfikowana przez użytkownika.
  • Przechowalnia (stage) — to miejsce pośrednie, między katalogiem roboczym a lokalną bazą danych. Dzięki niej można utrwalić tylko wybrane zmiany.
  • Katalog Git — to trzon lokalnego repozytorium. W nim Git przechowuje metadane o plikach oraz obiektową bazę danych. Ten katalog jest kopiowany podczas klonowania repozytorium.

Git install – instalacja Git

Jeżeli nie masz jeszcze Gita zainstalowanego lokalnie – szybko możesz to nadrobić.
W poniższym materiale znajdziesz instrukcję, jak można to zrobić.

➡ ZOBACZ 👉: Install Git – Instalacja Git, Windows, Ubuntu – Bash, GUI

Konfiguracja Git

Git posiada trzy poziomową konfigurację. Każdy kolejny poziom jest bardziej szczegółowy i można z niego nadpisać bardziej ogólną konfigurację. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest konfiguracja git’a sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git config – konfiguracja git, config, global, local

Aliasy

Dla często wykorzystywanych komend powstał mechanizm aliasów. Dzięki nim można przypisać wywołanie komendy, wraz z wszystkimi jej argumentami, do prostszego aliasu i korzystać z niego, jak z wbudowanej komendy.

Poniżej zaprezentowany jest przykład bardzo długiej komendy wyświetlającej historię zmian oraz przypisanie jej do aliasu.

git alias – git tutorial
Dużo łatwiej jest zapamiętać polecenie git hist niż jego pierwotną wersję.

Wywołanie zewnętrznej aplikacji z aliasu

Chcąc lepiej zintegrować gita z zewnętrznymi systemami, można posłużyć się wywołaniem zewnętrznej komendy z poziomu aliasu. W tym przypadku należy takie wywołanie poprzedzić wykrzyknikiem.

git alias – git tutorial

Klient GUI dla Gita

Niewątpliwie obsługa systemów z linii komend daje największe możliwości. Jednak nie zawsze mamy ochotę uczyć się na pamięć tych wszystkich komend. Dlatego w kursie będą pokazane alternatywne drogi: z poziomu konsoli i klienta GUI.

Git dorobił się już naprawdę pokaźnej listy aplikacji klienckich. Do tej pory najlepiej pracowało mi się na Windowsie na GitExtensions i TortoiseGit oraz na Linuksie na SmartGit i GitKraken.

Git tutorial | Git create repository– tworzenie nowego repozytorium

Jeżeli nie posiadasz jeszcze repozytorium, możesz je utworzyć na dwa sposoby: sklonować istniejące już repozytorium lub stworzyć całkowicie nowe.

Git init | Git init repo – utworzenie nowego repozytorium

W celu zainicjowania nowego repozytorium, będąc w docelowym katalogu, należy wykonać poniższą komendę.

git init

git init – git

Powyższy przykład pokazuje, że komenda git init wygeneruje strukturę nowego repozytorium w katalogu .git. Jednak jeżeli w katalogu znajdowały się już jakieś pliki, żeby rozpocząć śledzenie ich zmian, trzeba je jeszcze dodać do przechowalni (ang. stage) i je zapisać (ang. git commit).

Git clone – klonowanie repozytorium

W ramach tego materiału zajmujemy się przede wszystkim ogólnym zagadnieniem, jakim jest git – natomiast jeżeli chcesz poznać bliżej zagadnienie git clone, sprawdź w poniższy wpis.

➡ ZOBACZ 👉: Git branch | git branch create, rename, delete, clone, checkout, merge

Rejestrowanie zmian w repozytorium

Rejestrowanie zmian w repozytorium podzielone jest na kilka etapów bezpośrednio związanych z cyklem życia zmian.

Git log – historia zmian

Przyjrzymy się teraz bliżej możliwościom przeglądania historii projektu. Do przeglądania historii służy polecenie git log.

Domyślnie git log bez podania żadnych argumentów wyświetla zmiany od najnowszego do najstarszego.

Poniżej widać, zapisaną (ang. git commit) przeze mnie zmianę. Oprócz treści commit’a dostaliśmy także informację o hash’u commit’a. Możemy również podejrzeć, kiedy dany commit był utworzony i kto był jego autorem.

git log – git r

Polecenie log jest bardzo rozbudowane i zawiera wiele opcji konfiguracyjnych, ich pełną listę można znaleźć, korzystając z pomocy git help log.

Git commit | Git amend | Git add | Git status | Git diff

Git posiada kilka ciekawych opcji dotyczących rejestrowania zmian w repozytorium m.in. git commit lub git add. Jeżeli chcesz je bliżej poznać, sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git commit | git commit, amend, add, status, diff

Git tag – tagowanie źródeł

Tagowanie (etykietowanie źródeł) to mechanizm pozwalający na oznaczenie ważniejszych miejsc w historii zmian projektu. Najczęściej jest wykorzystywany do oznaczania wersji aplikacji (np. wersja 11.0, itp.). Jeżeli chcesz je bliżej poznać zagadnienie, jakim jest tagowanie w gicie, sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git tag – tagowanie w git, add, push, checkout

Gitignore – ignorowanie plików

W większości projektów mamy do czynienia z plikami, których nie chcemy wersjonować. Są to np. pliki generowane automatycznie lub przechowujące skeszowane dane. Dodanie ich do repozytorium powoduje tylko zaciemnienie obrazu wprowadzanych zmian.

Można, co prawda, pomijać tego typu pliki przy zatwierdzaniu zmian, jednak nie jest to zbyt pragmatyczne podejście. Dużo lepszym wyjściem jest oznaczenie takiej klasy plików jako ignorowane. Od tego momentu nie będą nawet widoczne jako pliki zmodyfikowane.

Mechanizm ignorowana plików oparty jest o plik tekstowy .gitignore. Poniżej przykładowa zawartość:

*.tmp
tmp

Kolejne klasy ignorowanych plików wpisujemy w osobnych linijkach. Pierwsza linijka odpowiedzialna jest za ignorowanie wszystkich plików o rozszerzeniu .tmp, natomiast druga za cały katalog tmp oraz jego zawartość.

Warto już na starcie zdefiniować, które pliki mają być ignorowane. Pozwoli to w przyszłości na uniknięcie zabawy z niepotrzebnymi plikami.

Ponieważ plik .gitignore jest zwykłym plikiem tekstowym przechowywanym w głównym katalogu repozytorium, on również może podlegać wersjonowaniu. Po jego dodaniu lub modyfikacji warto zakomitować naniesione zmiany, lub jego też oznaczyć do ignorowania 😉

Git revert – cofanie zmian

Git umożliwia kilka opcji, jeżeli chodzi o cofanie zmian. Jedną z nich jest git revert. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git revert sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git revert – git revert commit, revert last commit

Git reset – cofanie zmian

Bardziej rozbudowaną alternatywą dla git revert jest polecenie git reset. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git reset, sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git reset – Git reset hard, git reset to origin

Git branch – praca z gałęziami w Gicie

Git branch jest jedną z kluczowych funkcjonalności Gita, dzięki której stał się on tak popularny. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git branch i możliwości, jakie daje, sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git branch | git branch create, rename, delete, checkout, merge

Git checkout| Git switch – przełączanie się między gałęziami

Pracując z gałęziami (ang. git branches) umiejętność przełączania się między branch’ami jest bardzo przydatna. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git checkout oraz git switch, sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git checkout, git checkout remote branch, git switch

Git merge – scalanie gałęzi

Pracując na osobnych branch’ach dochodzimy do punktu, w którym chcemy złączyć nasze zmiany z resztą projektu. Do scalania zmian służy polecenie git merge. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git merge i dowiedzieć się jak radzić sobie z konfliktami (ang. merge conflicts), sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git merge, git merge branch

Git remote – praca ze zdalnym repozytorium

Dzięki wykorzystaniu możliwości zdalnego repozytorium można współpracować z innymi osobami, nie ograniczając się już tylko do pracy na jednym komputerze. Git umożliwia współpracę jednocześnie z kilkoma różnymi zdalnymi repozytoriami. Można z nich pobierać kod, wysyłać swoje zmiany oraz zarządzać gałęziami kodu itp.

Dodanie zdalnego repozytorium

Konfiguracja nowego zdalnego repozytorium polega na wywołaniu komendy w ogólnym formacie: git remote add <nazwa> <url>.

Od tego momentu nowe zdalne repozytorium jest już dowiązane do naszego lokalnego.

git remote add – git 

Git SSH

W dzisiejszych czasach bezpieczeństwo jest na miarę złota. Dlatego łącząc się ze zdalnym repozytorium, powinniśmy łączyć się, korzystając z bezpiecznego połączenia SSH (ang. git ssh).

➡ ZOBACZ 👉: Git SSH

Git push – wysłanie lokalnych zmian do zdalnego repozytorium

Posiadając zdalne repozytorium, wielokrotnie powstaje potrzeba, a czasem i konieczność wypychania (ang. git push) lokalnych zmian do zdalnego repozytorium. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git push sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git push – git integracja ze zdalnym repozytorium, git push, ssh, remote

Git fetch| Git pull – pobranie zmian ze zdalnego repozytorium

Wykonując różne operacje na gałęziach (ang. branch), konieczne jest odświeżanie stanu gałęzi (ang. git fetch) oraz scalanie brakujących danych ze swoim lokalnym repozytorium (ang. git pull). Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git fetch oraz git pull sprawdź poniższy wpis.

➡ ZOBACZ 👉: Git fetch vs. pull | Git fetch, git pull

Git Flow – czyli sposoby pracy z gałęziami

Wprowadzenie lekkiego i szybkiego modelu zarządzania gałęziami w Gicie przyczyniło się do powstania wielu różnych schematów pracy opartych o rozgałęzianie kodu. Jeżeli chcesz bliżej poznać zagadnienie, jakim jest git flowsprawdź poniższy wpis.

➡ ZOBACZ 👉: Git flow – wydajny system zarządzania gałęziami w Git

Git – System kontroli wersji – podsumowanie

W ramach tego materiału dowiedzieliśmy się, czym jest system kontroli wersji. Bliżej zapoznaliśmy się z Git’em i jego możliwościami. Jeżeli chcesz kontynuować swoją przygodę z gitem – to zapraszam do dodatkowych materiałów o GitHub’ie:

➡ ZOBACZ 👉: GitHub tutorial | GitHub desktop, GitHub actions


20+ BONUSOWYCH materiałów z programowania

e-book – „8 rzeczy, które musisz wiedzieć, żeby dostać pracę jako programista”,
e-book – „Java Cheat Sheet”,
checklista – „Pytania rekrutacyjne”
i wiele, wiele wiecej!

Jak zostać programistą

6 komentarzy
Share:

6 Comments

  1. Aki says:

    Cześć,
    „różnica między katalogiem roboczym a poczekalnią – git diff” – tego właśnie nie rozumiem. U mnie po dodaniu zmian (czyli po komendzie: git add plik) git diff nic nie pokazuje, działa dopiero jak dodam –staged. Natomiast samo git diff działa przy plikach w stanie: „Changes not staged for commit”. Wydaje mi się, że problemem dla mnie jest słowo „poczekalnia”, nie wiem dokładnie do którego stanu ono się odnosi: do tego zaraz po wniesieniu zmian w pliku czy po dodaniu ich do stage?

    A tutorial bardzo fajnie napisany:)

  2. Łukasz says:

    Fajny i czytelny poradnik, nie mniej jednak mam pewne problemy z pushowaniem zmian.
    Komenda `git push origin master` zwraca mi błąd:

    „`
    remote: error: refusing to update checked out branch: refs/heads/master
    remote: error: By default, updating the current branch in a non-bare repository is denied, because it will make the index and work tree inconsistent with what you pushed, and will require 'git reset –hard’ to match the work tree to HEAD.
    „`

    Jak push’uje na inny (nieaktywny) branch to wszystko działa, ale potem muszę robić merge na serwerze , więc to też bez sensu robota.

    Na zdalnym nie chcę mieć repozytorium jako –bare ponieważ:
    – zdarza mi się coś tam też bezpośrednio zmienić i commitować.
    – This operation must be run in a work tree`

    Czy ja czegoś tutaj nie rozumiem?

    1. Tomek says:

      Cześć Łukasz. Masz ciekawy przypadek.
      Na szybko widzę dwie opcje:
      1. Zostaw na serwerze repozytorium bare i zrób sobie niezależny katalog ze sklonowaną wersją – i tam wprowadzaj swoje zmiany.
      2. Zmień domyślną konfigurację w repozytorium na serwerze: git config –local receive.denyCurrentBranch updateInstead
      Wtedy będziesz mógł pushować swoje zmiany. Zanim jednak to zrobisz przeczytaj, co dokładnie oznacza ta konfiguracja:
      https://git-scm.com/docs/git-config/2.24.0#Documentation/git-config.txt-receivedenyCurrentBranch
      Powodzenia.

    1. Tomek says:

      Nie została jeszcze utrwalona w kontekście gita np. w commicie.
      To jest krok, kiedy np. odpalasz plik w notatniku i coś zmieniasz.
      Kolejny krok to dodanie zmiany do poczekalni, a potem już git commit i git push.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *