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.
Spis treści
- 1 Git – wprowadzenie
- 2 Systemy kontroli wersji kodu źródłowego
- 3 Lokalne systemy kontroli wersji
- 4 Scentralizowane systemy kontroli wersji
- 5 Rozproszone systemy kontroli wersji
- 6 Git | Git tutorial
- 7 Stany plików w Git
- 8 Git install – instalacja Git
- 9 Konfiguracja Git
- 10 Aliasy
- 11 Klient GUI dla Gita
- 12 Git tutorial | Git create repository– tworzenie nowego repozytorium
- 13 Git init | Git init repo – utworzenie nowego repozytorium
- 14 Git clone – klonowanie repozytorium
- 15 Rejestrowanie zmian w repozytorium
- 16 Git log – historia zmian
- 17 Git commit | Git amend | Git add | Git status | Git diff
- 18 Git tag – tagowanie źródeł
- 19 Gitignore – ignorowanie plików
- 20 Git revert – cofanie zmian
- 21 Git reset – cofanie zmian
- 22 Git branch – praca z gałęziami w Gicie
- 23 Git checkout| Git switch – przełączanie się między gałęziami
- 24 Git merge – scalanie gałęzi
- 25 Git remote – praca ze zdalnym repozytorium
- 26 Git SSH
- 27 Git push – wysłanie lokalnych zmian do zdalnego repozytorium
- 28 Git fetch| Git pull – pobranie zmian ze zdalnego repozytorium
- 29 Git Flow – czyli sposoby pracy z gałęziami
- 30 Git – System kontroli wersji – podsumowanie
- 31 20+ BONUSOWYCH materiałów z programowania
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).
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.
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.
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. CVS i Subversion) 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ą.
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.
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.
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
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.
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 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 flow, sprawdź 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!
6 Comments
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:)
Cześć! Dzięki za opinię. Tak, dobrze kombinujesz, poczekalnię rozumiemy jako stage.
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?
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.
co oznacza „ale zmiana o tym nie została jeszcze nigdzie zapisana” ?
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.