1/50
Praca z kodem - Mechanizmy wewnętrzne Gita
  • Witamy na trzeciej części wykładu – dziś zajrzymy pod maskę systemu Git.
  • Zrozumiemy, jak Git przechowuje dane i dlaczego jest tak szybki i niezawodny.
  • Poznamy model obiektowy: od sum kontrolnych po strukturę plików.
  • Zobaczymy, jak Git zarządza historią bez kopiowania całych plików.
  • Omówimy architekturę gałęzi i dowiemy się, dlaczego są one „lekkie".
  • Wiedza ta pozwoli Ci lepiej zrozumieć komunikaty błędów i świadomie zarządzać kodem.
Slajd 1

Zrozumienie wewnętrznych mechanizmów Gita jest kluczowe dla każdego programisty, który chce w pełni wykorzystać możliwości tego narzędzia. Wiedza o tym, jak Git przechowuje dane, pozwala lepiej pojąć przyczyny działania poszczególnych komend i przewidywać ich skutki.

Architektura Gita opiera się na kilku prostych, ale potężnych koncepcjach: nierelacyjnej bazie danych, sumach kontrolnych i niezmienności obiektów. Im głębiej zrozumiesz te fundamenty, tym łatwiej przyjdzie Ci rozwiązywanie konfliktów scalania i analiza złożonych historii projektu.

2/50
Model danych Gita: Magazyn obiektów
  • Git to w istocie prosta baza danych typu klucz-wartość (Content-Addressable Database).
  • Wszystkie dane są przechowywane jako obiekty w folderze .git/objects.
  • Wyróżniamy trzy główne typy obiektów: bloby (dane), drzewa (trees) i zatwierdzenia (commits).
  • Obiekty są niezmienne – raz zapisane nie zmieniają swojej treści.
  • Centralne repozytorium działa jak bezpieczny skarbiec dla Twojego kodu.
  • Dzięki temu Git zapewnia integralność danych na każdym etapie pracy.
Slajd 2

Content-Addressable Database oznacza, że dane są przechowywane pod kluczem będącym skrótem ich zawartości, a nie pod dowolnie nadaną nazwą. Dzięki temu Git ma gwarancję, że jeśli dwa obiekty mają identyczny hash, to ich treść jest taka sama, co eliminuje duplikację danych.

W praktyce oznacza to, że jeśli w repozytorium zmienisz tylko jeden plik, Git nie kopiuje całego projektu na nowo, a jedynie dodaje nowy obiekt zmienionego pliku. Pozostałe obiekty pozostają niezmienione, a nowy commit jedynie wskazuje na odpowiednie drzewa i blob.

3/50
Obiekt Blob: Przechowywanie treści plików
  • Blob (Binary Large Object) przechowuje wyłącznie treść Twojego pliku.
  • Nie zawiera on nazwy pliku, uprawnień ani daty utworzenia.
  • Każda unikalna treść otrzymuje własny identyfikator (skrót SHA-1).
  • Jeśli dwa pliki mają identyczną treść, Git zapisuje tylko jednego Bloba.
  • To podstawa mechanizmu usuwania duplikatów (deduplikacja danych).
  • Dzięki Blobom Twoje repozytorium zajmuje znacznie mniej miejsca na dysku.
Slajd 3

Blob to najprostszy typ obiektu w Gicie - przechowuje on wyłącznie zawartość pliku, bez żadnych metadanych. Gdy zmienisz zawartość pliku, Git tworzy nowy blob z nowym hashem, ale stary blob pozostaje w bazie danych, dopóki nie zostanie usunięty przez garbage collection.

To właśnie dzięki blobs Git potrafi tak szybko porównywać wersje plików - zamiast czytać cały plik, porównuje jedynie hashe blobów. Jeśli hasze są takie same, treść pliku jest identyczna, co pozwala na błyskawiczne określenie, które pliki uległy zmianie.

4/50
Obiekt Tree: Tworzenie struktury katalogów
  • Obiekt Tree (Drzewo) odpowiada za strukturę folderów w projekcie.
  • Działa jak cyfrowy spis treści: łączy nazwy plików z ich Blobami.
  • Drzewo może wskazywać na inne poddrzewa, tworząc hierarchiczną strukturę.
  • Zapisuje ono nazwy plików oraz ich uprawnienia (np. czy plik jest wykonywalny).
  • Każdy commit wskazuje na jedno główne drzewo (root tree) reprezentujące stan projektu.
  • To pozwala Gitowi błyskawicznie odtworzyć dowolny stan katalogów z historii.
Slajd 4

Obiekt Tree (drzewo) jest odpowiednikiem katalogu w systemie plików. Zawiera on listę wpisów, z których każdy wskazuje na blob (plik) lub inne drzewo (podkatalog) wraz z nazwą pliku, uprawnieniami (trybem) i hashem obiektu docelowego.

Drzewo to element, który nadaje strukturę flatowej bazie blobów. Bez drzew Git nie wiedziałby, który blob odpowiada któremu plikowi i w którym katalogu się znajduje. Dzięki temu mechanizmowi możliwe jest odtworzenie pełnej struktury katalogów z dowolnego momentu w historii.

5/50
Obiekt Commit: Łączenie wszystkiego w historię
  • Commit to trwały zapis stanu projektu w określonym momencie czasu.
  • Zawiera metadane: autora, datę, wiadomość oraz wskaźnik do obiektu Tree.
  • Każdy commit posiada wskaźnik do swojego "rodzica" (poprzedniego commita).
  • Węzły commitów tworzą historię projektu, umożliwiając podróże w czasie.
  • Commit to kotwica historyczna, która gwarantuje, że nic nie zginie.
  • Dzięki temu repozytorium staje się w pełni audytowalne i bezpieczne.
Slajd 5

Commit to kluczowy element łączący wszystkie pozostałe obiekty w spójną historię. Każdy commit zawiera referencję do obiektu drzewa (stan projektu), metadane (autor, datę, wiadomość) oraz wskaźnik do poprzedniego commita (rodzica). Dzięki temu powstaje łańcuch zatwierdzeń.

Commit z więcej niż jednym rodzicem oznacza scalenie (merge) dwóch gałęzi. To właśnie ta struktura umożliwia Gitowi śledzenie, skąd pochodzą zmiany i jak różne linie rozwoju łączą się ze sobą w czasie.

6/50
Haszowanie SHA-1: Cyfrowy dowód tożsamości
  • Git identyfikuje każdy obiekt za pomocą 40-znakowego kodu (sumy kontrolnej).
  • Zmienia treść pliku w unikalny ciąg znaków (np. 2a3b4c...).
  • Nawet najmniejsza zmiana (np. jedna kropka) generuje zupełnie nowy hasz.
  • Zapewnia to integralność danych - kody SHA-1 pozwalają wykryć każdą, nawet najmniejszą zmianę treści.
  • Pozwala Gitowi szybko porównywać pliki bez sprawdzania ich całej zawartości.
  • To fundament zaufania do danych w całym cyklu życia oprogramowania.
Slajd 6

Algorytm SHA-1 generuje 40-znakowy skrót heksadecymalny o długości 160 bitów. Mimo że SHA-1 nie jest już uznawany za kryptograficznie bezpieczny (istnieją ataki kolizyjne), Git przechodzi na SHA-256, aby zapewnić wyższy poziom bezpieczeństwa w nowych repozytoriach.

Warto wiedzieć, że Git używa skrótów nie tylko do identyfikacji obiektów, ale także do weryfikacji integralności danych. Jeśli podczas odczytu suma kontrolna obiektu nie zgadza się z jego hashem, Git natychmiast raportuje błąd, chroniąc przed cichym uszkodzeniem danych.

7/50
Referencje: Wskaźniki do commitów
  • Referencje to przyjazne nazwy dla trudnych do zapamiętania haszy SHA-1.
  • Przykładem referencji jest gałąź main lub tag v1.0.
  • Działają jak "karteczki samoprzylepne" doczepione do konkretnych commitów.
  • Gałęzie są wskaźnikami, które przesuwają się automatycznie przy każdym commicie.
  • Tagi są stacjonarne i służą do oznaczania ważnych momentów (np. wydań wersji).
  • HEAD to specjalny wskaźnik mówiący Gitowi, na której gałęzi obecnie pracujesz.
Slajd 7

Referencje w Gicie są przechowywane jako zwykłe pliki tekstowe w katalogu .git/refs/. Każdy taki plik zawiera hash SHA-1 commit, na który wskazuje. Istnieją trzy główne typy referencji: gałęzie (heads), tagi (tags) i zdalne (remotes).

HEAD jest specjalną referencją, która wskazuje nie bezpośrednio na commit, ale na inną referencję (np. refs/heads/main). Dzięki temu Git wie, która gałąź jest aktualnie aktywna, i przy każdym nowym commicie przesuwa zarówno HEAD, jak i gałąź do przodu.

8/50
DAG: Kształt historii w systemie Git
  • Historia Gita to skierowany graf acykliczny (Directed Acyclic Graph – DAG).
  • Każdy commit wskazuje wstecz na swojego przodka, tworząc strukturę łańcucha.
  • „Skierowany" oznacza jasny przepływ czasu; „acykliczny" – że historia nie zapętla się.
  • Ta struktura pozwala na rozwidlanie (branching) i łączenie (merging) historii.
  • Zrozumienie grafu to klucz do opanowania zaawansowanej współpracy zespołowej.
  • Dzięki temu Git potrafi logicznie powiązać zmiany z wielu linii czasu.
Slajd 8

DAG (Directed Acyclic Graph) to struktura danych, w której węzłami są commity, a krawędziami relacje rodzic-dziecko. Brak cykli oznacza, że nie można wrócić do wcześniejszego stanu przez podążanie za krawędziami - historia zawsze porusza się w przód w czasie.

Zrozumienie DAG jest kluczowe przy pracy z zaawansowanymi operacjami, takimi jak cherry-pick, rebase czy merge. Gdy wykonujesz rebase, Git przepisuje fragment grafu, tworząc nowe węzły (commity) i pomijając stare, co zmienia kształt historii.

9/50
Garbage Collection: Porządki w repozytorium
  • Z czasem w bazie danych Gita gromadzą się niepotrzebne ("dangling") obiekty.
  • Zbieranie śmieci (Garbage Collection - git gc) usuwa nieosiągalne obiekty i optymalizuje bazę.
  • Kompresuje historię, redukując rozmiar repozytorium i przyspieszając operacje.
  • Git wykonuje te operacje automatycznie, ale możesz je wymusić ręcznie.
  • Dba o to, aby Twoje repozytorium pozostało lekkie nawet po tysiącach zmian.
  • To proces dbający o wydajność i porządek w strukturze danych projektu.
Slajd 9

Garbage collection w Gicie odpowiada za usuwanie obiektów, do których nie prowadzi żadna referencja (dangling objects). Dzieje się tak na przykład po wykonaniu git commit --amend lub git rebase, gdy stare commity zostają zastąpione nowymi.

Komenda git gc uruchamiana automatycznie po wykonaniu pewnych operacji (np. git fetch, git merge) lub ręcznie przez użytkownika. Oprócz usuwania nieosiągalnych obiektów, gc także pakuje luźne obiekty w pliki .pack, co znacząco redukuje miejsce na dysku.

10/50
Inspekcja obiektów: Komenda git cat-file
  • Chcesz zobaczyć, co naprawdę kryje się pod danym haszem?
  • Użyj polecenia `git cat-file`, aby "prześwietlić" bazę danych obiektów.
  • Opcja `-p` (pretty print) wyświetla czytelną treść Bloba, Tree lub Commita.
# Zobacz treść obiektu o konkretnym haszu
git cat-file -p 2a3b4c5...

# Sprawdź typ obiektu (blob, tree, commit)
git cat-file -t 2a3b4c5...
            
  • To narzędzie daje pełną przejrzystość i pomaga zrozumieć, jak działa Git.
Slajd 10

git cat-file to narzędzie niskiego poziomu (plumbing), które pozwala na bezpośredni odczyt obiektów z bazy danych Gita. Jest niezastąpione przy debugowaniu problemów z repozytorium i nauce wewnętrznych mechanizmów systemu.

Dzięki opcji -p (pretty print) możesz zobaczyć zawartość dowolnego obiektu w czytelnej formie, niezależnie od tego, czy jest to blob, tree, commit, czy tag. Opcja -t pozwala sprawdzić typ obiektu, a -s jego rozmiar. To jak latarka w ciemnym korytarzu bazy danych Gita.

11/50
Packfile: Kompresja i wydajność zapisu
  • Przechowywanie każdego pliku osobno byłoby nieefektywne na dłuższą metę.
  • Git łączy wiele obiektów w jeden skompresowany plik .pack.
  • Wykorzystuje kodowanie delta, zapisując tylko różnice między wersjami.
  • To sprawia, że ogromna historia projektu zajmuje zaskakująco mało miejsca.
  • Mechanizm ten jest kluczowy przy szybkim przesyłaniu danych na serwer (push/pull).
  • Zmienia on bazę danych w wysoce zoptymalizowany system archiwizacji.
Slajd 11

Mechanizm packfile to jedna z najważniejszych optymalizacji wydajnościowych Gita. Zamiast przechowywać każdy obiekt osobno jako osobny plik (luźny obiekt), Git pakuje wiele obiektów w jeden skompresowany plik .pack z indeksem .idx.

Podczas pakowania Git stosuje kodowanie delta, które przechowuje tylko różnice między podobnymi obiektami. Dzięki temu przechowanie tysiąca wersji tego samego pliku może zająć tylko kilkukrotność rozmiaru pojedynczej wersji, a nie tysiąckrotność.

12/50
Index: Most między projektem a repozytorium
  • Indeks (często zwany obszarem stagingu – Staging Area) to wirtualna „poczekalnia" dla zmian.
  • To plik binarny, który przechowuje mapę plików przygotowanych do następnego zatwierdzenia.
  • Pozwala na precyzyjną kontrolę: wybierasz dokładnie, co znajdzie się w historii.
  • Git porównuje Twój folder roboczy z indeksem, aby wykryć wprowadzone zmiany.
  • To niewidoczny rejestr, który napędza komendy `git add` oraz `git status`.
  • Dzięki niemu praca dewelopera jest zorganizowana i wolna od przypadkowych błędów.
Slajd 12

Indeks (index), zwany też staging area lub cache, to plik binarny .git/index, który przechowuje informacje o wszystkich plikach śledzonych przez Gita. Każdy wpis w indeksie zawiera hash bloba, znacznik czasu (mtime), rozmiar pliku oraz uprawnienia.

Gdy wykonujesz git status, Git porównuje trzy stany: HEAD (ostatni commit), indeks (staging) i working directory (folder roboczy). Dzięki temu możesz precyzyjnie kontrolować, które zmiany trafią do następnego commita, a które pozostaną tylko lokalnie.

13/50
Mechanika git add: Tworzenie Blobów
  • Co dzieje się pod maską, gdy wpisujesz `git add`?
  • Git natychmiast haszuje treść pliku i tworzy nowy obiekt blob.
  • Zapisuje ten obiekt w folderze .git/objects, zapewniając jego trwałość.
  • Następnie aktualizuje indeks, przypisując nazwę pliku do nowego hasza.
  • To proces „zamrażania" treści jeszcze przed finalnym zatwierdzeniem zmiany.
  • Dzięki temu Twoja praca jest zabezpieczona niemal w czasie rzeczywistym.
Slajd 13

Proces git add to pierwszy krok w utrwalaniu zmian. Git oblicza hash SHA-1 treści pliku, zapisuje blob w .git/objects, a następnie aktualizuje wpis w indeksie, przypisując ścieżkę pliku do nowego hasha. Jeśli plik już istniał w indeksie, stary wpis jest zastępowany.

Warto wiedzieć, że git add można wykonać z różnymi opcjami: -A (wszystkie zmiany, w tym usunięcia), -p (interaktywne dodawanie fragmentów pliku) czy -n (suchy bieg bez faktycznego dodawania). Dzięki temu masz pełną kontrolę nad tym, co trafia do indeksu.

14/50
Mechanika git commit: Tworzenie Drzew i Commitów
  • Komenda `commit` to drugi krok procesu utrwalania zmian.
  • Git bierze aktualny stan indeksu i generuje z niego obiekt drzewa (Tree).
  • Następnie tworzy obiekt zatwierdzenia (Commit), który wskazuje na to właśnie drzewo.
  • Do zatwierdzenia dodawane są metadane: autor, czas i wskaźnik do „rodzica".
  • Na końcu Git aktualizuje referencję gałęzi (np. main) na ten nowy commit.
  • To elegancki, dwuetapowy proces finalizacji historii Twojej pracy.
Slajd 14

Proces git commit przebiega dwuetapowo: najpierw Git tworzy obiekt drzewa (tree) na podstawie bieżącego indeksu, a następnie tworzy obiekt commita, który wskazuje na to drzewo. Commit otrzymuje także informacje o autorze, dacie i wiadomości z twojego edytora lub parametru -m.

Każdy commit musi mieć co najmniej jednego rodzica. Pierwszy commit w repozytorium (root commit) nie ma rodzica. Podczas scalania tworzony jest commit z dwoma rodzicami (merge commit). Liczba rodziców wpływa na kształt grafu historii i sposób, w jaki Git interpretuje zmiany.

15/50
Integralność obiektów i ochrona przed uszkodzeniem
  • Git jest zbudowany z myślą o absolutnym bezpieczeństwie Twojego kodu.
  • Każdy obiekt jest chroniony przez sumę kontrolną przed uszkodzeniem bitowym.
  • Jeśli treść pliku ulegnie zmianie poza Gitem, hasz przestanie pasować.
  • System natychmiast wykryje niespójność, zapobiegając utracie danych.
  • To jak nieprzebijalna tarcza chroniąca historię projektu przed błędami sprzętu.
  • Możesz ufać, że to, co zapisałeś rok temu, jest dokładnie tym, co odczytasz dzisiaj.
Slajd 15

Mechanizm integralności Gita opiera się na założeniu, że dane są przechowywane w sposób niezmienny. Jeśli jakikolwiek obiekt w .git/objects zostanie uszkodzony (np. przez błąd dysku), jego hash SHA-1 nie będzie pasował do treści, co Git natychmiast wykryje.

Komenda git fsck (file system check) skanuje całą bazę obiektów i weryfikuje integralność każdego z nich. W przypadku wykrycia uszkodzenia Git poinformuje o błędzie i wskaże, który obiekt jest uszkodzony. Jeśli masz kopię repozytorium na zdalnym serwerze, możesz pobrać brakujące obiekty.

16/50
Reflog: Ostateczna siatka bezpieczeństwa
  • Skasowałeś gałąź przez pomyłkę? "Zgubiłeś" ważny commit po resecie?
  • `git reflog` to kronika ruchów wskaźnika HEAD na Twoim komputerze.
  • Zapisuje on każdą zmianę pozycji HEAD, nawet jeśli nie jest ona częścią historii.
  • Pozwala odnaleźć i przywrócić commity, które wydają się być stracone.
  • To "koło ratunkowe", które wyciągnie Cię z najtrudniejszych sytuacji.
  • Pamiętaj: w Gicie rzadko kiedy coś naprawdę ginie bezpowrotnie.
Slajd 16

Reflog to lokalny dziennik zmian referencji, przechowywany w .git/logs/. Znajdują się w nim wpisy o każdej zmianie HEAD i poszczególnych gałęzi, nawet jeśli te zmiany nie są już częścią widocznej historii. Domyślnie reflog przechowuje wpisy przez 90 dni.

Reflog może uratować cię w sytuacji, gdy przypadkowo zresetujesz gałąź, usuniesz commit lub zgubisz się w rebase. Wpisz git reflog, znajdź hash commita sprzed katastrofy i użyj git reset --hard <hash>, aby cofnąć zmiany. Pamiętaj, że reflog istnieje tylko lokalnie.

17/50
Powiązania obiektów: Od Commita do Bloba
  • Repozytorium to gęsta sieć powiązań między różnymi typami obiektów.
  • Ścieżka jest jasna: Commit -> Tree -> Sub-tree -> Blob.
  • Ta struktura pozwala Gitowi precyzyjnie odtworzyć stan dowolnego pliku w czasie.
  • Dzięki temu połączeniu historia jest w pełni przejrzysta i mierzalna.
  • Wizualizacja tych powiązań pomaga zrozumieć architekturę całego systemu.
  • Każdy element projektu jest częścią większej, logicznej i spójnej układanki.
Slajd 17

Pełna ścieżka powiązań obiektów w Gicie wygląda następująco: Commit → Tree → (Tree lub Blob). Każdy commit wskazuje na dokładnie jedno drzewo główne (root tree), które reprezentuje stan całego projektu w momencie zatwierdzenia.

Rekurencyjne rozwinięcie drzewa głównego daje kompletną mapę wszystkich plików i katalogów w projekcie w danym momencie. Dzięki temu Git może błyskawicznie odtworzyć dowolny stan projektu, podążając za wskaźnikami od commita przez drzewa do blobów.

18/50
Kodowanie Delta: Jak Git oszczędza miejsce
  • Zamiast zapisać dwie pełne kopie pliku z jedną zmianą, Git szuka różnic.
  • Kodowanie delta zapisuje oryginał i tylko listę zmian ("diff") dla kolejnych wersji.
  • To sprawia, że praca nad dużymi projektami tekstowymi jest niezwykle wydajna.
  • Mechanizm ten działa najlepiej wewnątrz plików typu Packfile podczas archiwizacji.
  • Zoptymalizowane zarządzanie rozmiarem pozwala na szybkie operacje sieciowe.
  • Git to mistrz oszczędności, który nie marnuje ani jednego bajtu Twojego dysku.
Slajd 18

Kodowanie delta w Gicie działa na poziomie packfile. Git porównuje ze sobą podobne obiekty i zapisuje tylko różnice między nimi (delta), a nie pełną treść każdego obiektu. Algorytm doboru obiektów do porównania opiera się na heurystykach, które maksymalizują kompresję.

Podczas operacji push i pull Git przesyła tylko pakiety (pack files) z kodowaniem delta, co znacząco redukuje ilość danych przesyłanych przez sieć. To dlatego nawet bardzo duże repozytoria z długą historią mogą być klonowane w ciągu kilku sekund, jeśli łącze jest szybkie.

19/50
Przykład praktyczny: Naprawa uszkodzonego repozytorium
  • Co jeśli ręcznie skasujesz plik z folderu .git/objects?
  • Narzędzie `git fsck` (file system check) wykryje brakujący lub uszkodzony obiekt.
  • Jeśli masz kopię na GitHub, możesz po prostu pobrać brakujące dane.
  • Zrozumienie tej struktury pozwala Ci na samodzielną diagnostykę błędów.
  • Git oferuje mechanizmy "samoleczenia" poprzez synchronizację z innymi kopiami serwera.
  • To uczy dyscypliny inżynierskiej i daje pewność w zarządzaniu danymi projektu.
Slajd 19

git fsck (file system check) to narzędzie do weryfikacji integralności bazy danych Gita. Skanuje ono wszystkie obiekty w .git/objects i sprawdza, czy ich treść odpowiada hashom SHA-1. Wykrywa również obiekty wiszące (dangling), czyli takie, do których nie prowadzi żadna referencja.

W przypadku uszkodzenia repozytorium pierwszą linią obrony jest pobranie brakujących obiektów ze zdalnego serwera (git fetch). Jeśli to nie pomoże, możesz spróbować przywrócić obiekty z kopii zapasowej katalogu .git. Regularne wykonywanie git fsck to dobra praktyka inżynierska.

20/50
HEAD i Index: Ostatnie ogniwo
  • HEAD i indeks muszą współpracować, aby proces zapisu zmian był spójny.
  • HEAD wskazuje, gdzie w historii „stoisz"; indeks pokazuje, co „planujesz" zapisać.
  • Po udanym zatwierdzeniu podążają one w tym samym kierunku, synchronizując swój stan.
  • To precyzyjne narzędzie dewelopera, gwarantujące wysoką jakość aktualizacji.
  • Zrozumienie ich powiązania kończy drogę od nowicjusza do świadomego architekta.
  • Znasz już mechanizmy leżące u podstaw każdego systemu kontroli wersji.
Slajd 20

HEAD to specjalny wskaźnik, który determinuje, na którym commicie aktualnie pracujesz. W normalnym przypadku HEAD wskazuje na gałąź (np. refs/heads/main), która z kolei wskazuje na konkretny commit. W stanie detached HEAD wskaźnik kieruje bezpośrednio na commit.

Indeks to pomost między twoim folderem roboczym a następnym commitm. Gdy HEAD i indeks są zsynchronizowane (po udanym commicie), oznacza to, że ostatnie zatwierdzenie odzwierciedla stan indeksu. Rozbieżność między nimi sygnalizuje, że masz niezatwierdzone zmiany w indeksie.

21/50
Podsumowanie hierarchii obiektów
  • Struktura Gita to piękny graf, zaczynający się od pojedynczego Commita.
  • Każdy element: Commit, Tree i Blob ma swoje miejsce i jasną odpowiedzialność.
  • Ta architektura zapewnia pełną audytowalność i przejrzystość zmian w kodzie.
  • Nie traktuj już Gita jak czarnej skrzynki - teraz znasz logikę jego działania.
  • Głębia techniczna tej wiedzy zaprocentuje przy rozwiązywaniu trudnych konfliktów.
  • Jesteś gotowy, aby przejść od prostego zapisywania plików do profesjonalnego modelowania danych.
Slajd 21

Hierarchia obiektów Gita tworzy elegancką, samospójną strukturę, w której każdy element ma jasno określoną rolę. Commit przechowuje migawkę projektu z metadanymi, Tree odwzorowuje strukturę katalogów, a Blob zawiera czystą treść plików.

Ta architektura sprawia, że Git jest niezwykle wydajny: porównanie dwóch commitów sprowadza się do porównania dwóch drzew, a zmiana jednego pliku wymaga dodania tylko jednego nowego bloba i zaktualizowania drzew na ścieżce do niego. Reszta obiektów pozostaje współdzielona.

22/50
Wnętrzności Gita - Koniec części pierwszej
  • Właśnie opanowałeś fundamenty "silnika" systemu kontroli wersji.
  • Znasz rolę Bloba, Tree, Commita oraz znaczenie sum kontrolnych SHA-1.
  • Zrozumiałeś, jak Git dba o miejsce na dysku i integralność Twojej pracy.
  • Ta wiedza czyni Cię bardziej świadomym i pewnym siebie programistą.
  • W drugiej połowie wykładu przejdziemy do praktyki: gałęzi i nowoczesnych modeli pracy.
  • Przygotuj się na poznanie "supermocy" Gita: równoległego tworzenia kodu.
Slajd 22

Pierwsza część wykładu dostarczyła ci solidnych podstaw teoretycznych z zakresu wewnętrznej architektury Gita. Znasz już różnicę między blobem, drzewem i commitm, rozumiesz rolę sum kontrolnych SHA-1 oraz mechanizmy kompresji i integralności danych.

Teoria jest jednak tylko wstępem do praktyki. W drugiej części wykładu skupisz się na gałęziach, które są najpotężniejszym narzędziem Gita do równoległej pracy nad kodem. Zrozumienie, jak gałęzie działają na poziomie mechanicznym, pozwoli ci swobodnie nimi manipulować.

23/50
Czym jest gałąź (Branching)?
  • Gałąź to możliwość pracy nad różnymi wersjami kodu w tym samym czasie.
  • Pozwala na izolację nowych funkcji bez ryzyka zepsucia stabilnego programu.
  • Wyobraź sobie gałąź jako równoległą rzeczywistość, która żyje własnym życiem.
  • W dowolnym momencie możesz połączyć te światy, scalając zmiany.
  • To podstawa pracy zespołowej - każdy może tworzyć kod bez przeszkadzania innym.
  • Gałęzie w Gicie są darmowe i niezwykle szybkie (to tylko małe wskaźniki).
Slajd 23

Branching (gałęzie) to mechanizm umożliwiający rozwijanie kodu w izolacji od głównej linii projektu. W Gicie gałąź to jedynie ruchomy wskaźnik do konkretnego commita, który przesuwa się automatycznie przy każdym nowym zatwierdzeniu dokonanym na tej gałęzi.

Dzięki gałęziom możesz pracować nad nową funkcją, eksperymentować z refaktoryzacją lub naprawiać błąd w bezpiecznym środowisku, bez ryzyka destabilizacji głównego kodu. Po zakończeniu pracy łączysz gałąź z powrotem za pomocą merge lub rebase.

24/50
Koszt tworzenia gałęzi: Lekkie wskaźniki
  • W starszych systemach gałąź oznaczała kopiowanie całego projektu.
  • W Gicie gałąź to tylko mały plik tekstowy (41 bajtów) z haszem commita.
  • Dlatego tworzenie i przełączanie gałęzi jest niemal natychmiastowe.
  • Możesz tworzyć dziesiątki gałęzi dziennie bez obaw o wydajność komputera.
  • To pozwala na pracę w modelu "gałąź dla każdego zadania" (feature-per-task).
  • Git jest mistrzem skalowania - poradzi sobie z milionami gałęzi bez zadyszki.
Slajd 24

Koszt stworzenia gałęzi w Gicie jest znikomy, ponieważ wymaga jedynie zapisania 41 bajtów (hash 40 znaków + znak nowej linii) w pliku w katalogu .git/refs/heads/. Dla porównania, w starszych systemach CVS czy SVN założenie gałęzi oznaczało kopiowanie całego repozytorium.

Ta lekkość gałęzi zachęca do tworzenia ich często i dla każdego zadania z osobna. W nowoczesnych przepływach pracy (GitFlow, GitHub Flow) gałęzie są zakładane nawet dla pojedynczego zgłoszenia (issue) i usuwane po scaleniu, co utrzymuje historię czystą i przejrzystą.

25/50
Komenda git branch: Listowanie i nawigacja
  • To główne narzędzie do zarządzania gałęziami w Twoim repozytorium.
  • Samo `git branch` wyświetla listę dostępnych lokalnie gałęzi.
  • Gwiazdka (*) wskazuje gałąź, na której aktualnie się znajdujesz.
# Wyświetl lokalne gałęzie
git branch

# Wyświetl wszystkie gałęzie (lokalne i zdalne)
git branch -a
            
  • Dzięki temu zawsze wiesz, w jakim kontekście projektu się poruszasz.
  • Pamiętaj o regularnym sprawdzaniu stanu swoich gałęzi przed każdą dużą operacją.
Slajd 25

Komenda git branch bez argumentów wyświetla listę lokalnych gałęzi, oznaczając aktywną gwiazdką. Opcja -v dodaje ostatni commit na każdej gałęzi, -vv pokazuje także śledzone gałęzie zdalne, a -a wyświetla wszystkie gałęzie (lokalne i zdalne).

Regularne przeglądanie gałęzi pomaga utrzymać porządek w repozytorium. Gałęzie, które zostały już scalone i nie są już potrzebne, powinny być usuwane komendą git branch -d, aby nie zaśmiecać listy i nie wprowadzać zamieszania w zespole.

26/50
Tworzenie pierwszej gałęzi z git branch
  • Tworzenie nowej gałęzi to otwarcie nowej ścieżki rozwoju Twojego projektu.
  • Operacja ta jest bezpieczna - nie zmienia plików w Twoim folderze roboczym.
  • Dopiero przełączenie się na nową gałąź pozwoli Ci na niej pracować.
# Stworzenie nowej gałęzi o nazwie 'nowa-funkcja'
git branch nowa-funkcja
            
  • Zaleca się stosowanie opisowych nazw gałęzi, oddających naturę zadania.
  • Dzięki izolacji możesz eksperymentować bez obawy o stabilność głównego kodu.
  • Zrozumienie tego procesu to pierwszy krok do nowoczesnej współpracy w zespole.
Slajd 26

Tworzenie gałęzi komendą git branch <nazwa> powoduje utworzenie nowego wskaźnika do aktualnego commita. Nowa gałąź dziedziczy całą historię bieżącej gałęzi, ale od tego momentu może rozwijać się niezależnie.

Wybór odpowiedniej nazwy gałęzi to ważna konwencja zespołowa. Popularne schematy to: feature/nazwa-funkcji, bugfix/nazwa-bledu, hotfix/nagły-problem. Dobre nazewnictwo ułatwia późniejsze identyfikowanie celu danej gałęzi i automatyzację procesów CI/CD.

27/50
Komendy checkout i switch: Zmiana rzeczywistości
  • Aby zacząć pracę na innej gałęzi, musisz na nią "przeskoczyć".
  • Używamy do tego komendy `git checkout` lub nowszej, jaśniejszej `git switch`.
  • Git natychmiast zaktualizuje pliki na Twoim dysku, by pasowały do wybranej gałęzi.
  • Portal między różnymi stanami projektu pozwala na błyskawiczne zmiany zadań.
  • Dba o integralność plików, nie pozwalając na przełączenie przy niezapisanych zmianach.
  • To fundament elastyczności, pozwalający deweloperowi sprawnie obsługiwać wiele wątków.
Slajd 27

Komenda git checkout <gałąź> zmienia aktualnie aktywną gałąź i aktualizuje pliki w folderze roboczym do stanu z tej gałęzi. Nowsza komenda git switch została wprowadzona, aby rozdzielić funkcjonalność checkout (przełączanie gałęzi) od przywracania plików.

Podczas przełączania gałęzi Git sprawdza, czy nie masz niezapisanych zmian w folderze roboczym. Jeśli takie istnieją i kolidują z plikami na docelowej gałęzi, Git odmówi przełączenia, chroniąc przed utratą danych. W takiej sytuacji użyj git stash, aby tymczasowo odłożyć zmiany.

28/50
Scalanie Fast-Forward: Ścieżka liniowa
  • To najprostszy i najczystszy sposób łączenia zmian w systemie Git.
  • Występuje, gdy Twoja główna gałąź nie zmieniła się od czasu utworzenia feature brancha.
  • Git po prostu przesuwa wskaźnik gałęzi do przodu (jak na bieżni).
  • Nie powstaje żaden dodatkowy "merge commit" - historia pozostaje prostą linią.
  • To idealny scenariusz, gwarantujący czytelność i prostotę dziennika zmian.
  • Dzieje się to automatycznie, gdy tylko jest to technicznie możliwe.
Slajd 28

Fast-forward merge to najprostszy typ scalania, który występuje, gdy gałąź źródłowa jest bezpośrednim potomkiem gałęzi docelowej. Git po prostu przesuwa wskaźnik gałęzi docelowej do przodu, bez tworzenia dodatkowego commita scalającego.

Ten typ scalania jest preferowany w przepływach pracy promujących liniową historię, takich jak GitHub Flow. Aby wymusić fast-forward, możesz użyć opcji --ff-only w komendzie git merge, która przerwie scalanie, jeśli nie jest możliwe wykonanie fast-forward.

29/50
3-Way Merge: Integrowanie różnych historii
  • Co gdy obie gałęzie ruszyły do przodu równolegle?
  • Git wykonuje tzw. scalanie trójstronne (3-way merge).
  • Analizuje wspólnego przodka oraz końce obu gałęzi, by połączyć je w całość.
  • Tworzony jest specjalny "merge commit", który ma dwóch rodziców.
  • Pozwala to na pogodzenie różnych ścieżek rozwoju bez utraty żadnej informacji.
  • Tak buduje się złożone projekty, w których wielu ludzi pracuje jednocześnie.
Slajd 29

Scalanie trójstronne (3-way merge) jest wykonywane, gdy obie gałęzie mają rozbieżną historię od czasu ich rozwidlenia. Git analizuje trzy punkty: wspólnego przodka (merge base), koniec gałęzi docelowej i koniec gałęzi źródłowej, a następnie tworzy nowy commit scalający z dwoma rodzicami.

Proces 3-way merge polega na zastosowaniu dwóch zestawów zmian (z obu gałęzi) do wspólnego przodka. Jeśli te same linie zostały zmienione w obu gałęziach, powstaje konflikt, który musi rozwiązać człowiek. W przeciwnym razie scalanie przebiega automatycznie.

30/50
Konflikty scalania: Kiedy rzeczywistości się zderzają
  • Konflikt to moment, w którym Git potrzebuje pomocy człowieka.
  • Pojawia się, gdy dwie osoby zmieniły tę samą linię w tym samym pliku.
  • System zaznacza sporne miejsca specjalnymi znacznikami (conflict markers).
  • To nie błąd - to mechanizm chroniący przed przypadkowym nadpisaniem kodu.
  • Zmusza dewelopera do podjęcia świadomej decyzji inżynierskiej.
  • Zrozumienie przyczyn konfliktu to klucz do dojrzałej pracy zespołowej.
Slajd 30

Konflikty scalania pojawiają się, gdy Git nie może automatycznie połączyć zmian z dwóch gałęzi. Typowym scenariuszem jest sytuacja, w której dwie osoby edytowały tę samą linię w tym samym pliku. Git oznacza miejsce konfliktu znacznikami <<<<<<<, ======= i >>>>>>>.

Rozwiązywanie konfliktów wymaga ręcznej ingerencji: musisz edytować plik, usunąć znaczniki konfliktu i pozostawić poprawną wersję kodu. Po rozwiązaniu wszystkich konfliktów dodajesz pliki do indeksu (git add) i finalizujesz scalenie (git commit). To proces twórczy, nie mechaniczny.

31/50
Rozwiązywanie konfliktów i finalizacja
  • Rozwiązywanie konfliktów to standardowy proces naprawy logiki kodu.
  • Musisz ręcznie edytować plik, usunąć znaczniki konfliktu i wybrać poprawną wersję.
  • Po poprawce używasz `git add`, by zatwierdzić naprawiony plik w indeksie.
  • Ostatnim krokiem jest wykonanie zatwierdzenia (commit) kończącego proces scalania.
  • To proces kreatywny, który przywraca stabilność całemu projektowi.
  • Każdy rozwiązany konflikt to cenna lekcja o strukturze Twojego oprogramowania.
Slajd 31

Proces rozwiązywania konfliktów zaczyna się od identyfikacji plików z konfliktami za pomocą git status. Pliki w stanie both modified wymagają twojej uwagi. Następnie otwierasz każdy taki plik w edytorze i podejmujesz decyzję, która wersja kodu jest poprawna.

Po edycji wszystkich skonfliktowanych plików i usunięciu znaczników konfliktu używasz git add, aby oznaczyć je jako rozwiązane. Na koniec wykonujesz git commit, który tworzy merge commit z dwoma rodzicami. Jeśli w trakcie rozwiązywania uznasz, że to zbyt trudne, możesz przerwać git merge --abort.

32/50
Usuwanie gałęzi: Higiena repozytorium
  • Po udanym scaleniu gałąź robocza nie jest już potrzebna (staje się martwa).
  • Zaleca się usuwanie nieużywanych gałęzi, by utrzymać porządek w projekcie.
  • Działa to jak cyfrowe sprzątanie, zapobiegając chaosowi w historii.
# Usuń gałąź, która została już scalona
git branch -d funkcja-gotowa
            
  • Dbałość o czyste repozytorium to cecha profesjonalnego programisty.
  • Pozwala skupić się na tym, co jest aktualnie ważne i aktywne.
Slajd 32

Usuwanie gałęzi po scaleniu to standardowa praktyka utrzymująca porządek w repozytorium. Gałęzie, które zostały już scalone do głównej linii, nie są już potrzebne, a ich pozostawienie powoduje chaos i utrudnia nawigację.

Komenda git branch -d usuwa gałąź tylko wtedy, gdy została już scalona. Jeśli chcesz usunąć gałąź, która nie została scalona (i stracić jej zmiany), użyj git branch -D (wielkie D). Zawsze upewnij się, że zmiany z usuwanej gałęzi są bezpiecznie scalone gdzie indziej.

33/50
Wyjście awaryjne: git merge --abort
  • Scalanie poszło źle? Konflikty są zbyt trudne na ten moment?
  • Użyj "przycisku paniki": `git merge --abort`.
  • Git natychmiast przerwie scalanie i wróci do stanu sprzed operacji.
  • Zapewnia to bezpieczny odwrót, chroniąc przed pomyłkami w pośpiechu.
  • To dowód na to, że w Gicie błędy niemal nigdy nie muszą być ostateczne.
  • Daje poczucie pełnej kontroli nad losem Twojego kodu w trudnych chwilach.
Slajd 33

Opcja --abort w komendzie git merge to mechanizm bezpieczeństwa, który pozwala przerwać scalanie w dowolnym momencie przed finalizacją. Git przywraca stan sprzed rozpoczęcia scalania, cofając wszystkie zmiany w folderze roboczym i indeksie.

Warto wiedzieć, że istnieje także git merge --quit, który różni się od --abort tym, że nie cofa zmian w folderze roboczym, a jedynie usuwa znaczniki stanu scalania. --abort jest bezpieczniejszy, ponieważ w pełni przywraca poprzedni stan repozytorium.

34/50
Wizualizacja historii: git log --graph
  • Tekstowa lista commitów bywa mało czytelna przy wielu gałęziach.
  • Dodaj opcję `--graph`, aby zobaczyć wizualną strukturę Twojego projektu.
  • Kolorowe linie i kółka pokażą, gdzie gałęzie powstały i gdzie się łączą.
# Zobacz graficzną mapę metra swojej historii
git log --oneline --graph --all
            
  • To narzędzie daje pełną jasność co do ścieżek rozwoju całego zespołu.
  • Dzięki niemu historia staje się piękną, wielowymiarową opowieścią o projekcie.
Slajd 34

git log --graph to potężne narzędzie wizualizacji historii, które rysuje na terminalu kolorowy graf commitów. Opcja --oneline skraca każdy wpis do jednej linii, --all pokazuje wszystkie gałęzie, a --decorate dodaje etykiety gałęzi i tagów.

Dla jeszcze lepszej wizualizacji warto użyć dedykowanych narzędzi, takich jak gitk (wbudowane GUI), git log --pretty=format z własnym formatowaniem, lub zewnętrznych programów, jak Sourcetree, GitKraken czy tig (konsolowy). Wizualizacja grafu znacznie ułatwia zrozumienie złożonej historii.

35/50
Merge czy Rebase? Dwie filozofie
  • Istnieją dwa główne sposoby integracji zmian: scalanie (Merge) i przebudowa (Rebase).
  • Merge zachowuje pełną, prawdziwą historię wraz z zatwierdzeniami scalającymi.
  • Rebase tworzy czystą, liniową opowieść, „przepisując" Twoje zmiany na nowy fundament.
  • Wybór zależy od standardów zespołu i pożądanej czytelności logów.
  • Zrozumienie wad i zalet obu metod to cecha zaawansowanego użytkownika.
  • Dobre podejście pozwala uniknąć tzw. „warkocza" (nadmiaru splotów) w historii projektu.
Slajd 35

Merge i Rebase to dwie różne strategie integrowania zmian, każda z własnymi zaletami i wadami. Merge zachowuje oryginalną historię z wszystkimi rozgałęzieniami, co jest zgodne z prawdą, ale może tworzyć skomplikowany graf. Rebase tworzy czystą, liniową historię, ale zmienia oryginalne commity.

Wybór między merge a rebase zależy od standardów zespołu i charakteru projektu. W GitHub Flow preferuje się merge, ponieważ zachowuje kontekst gałęzi. W przepływach wymagających czystej historii, jak upstream open-source, często stosuje się rebase przed scaleniem.

36/50
Komenda git rebase: Prostowanie historii
  • Rebase pozwala "przenieść" Twoją pracę na sam początek aktualnego stanu projektu.
  • Działa jak wyrównywacz, usuwając zbędne rozwidlenia z głównego widoku.
  • Sprawia, że praca wygląda, jakby była od początku pisana w linii prostej.
  • To potężne narzędzie do polerowania historii przed wysłaniem jej na serwer.
  • Zapewnia wysoką estetykę i profesjonalizm w dzienniku zmian.
  • Zrozumienie rebase to wejście na wyższy poziom mistrzostwa w systemie Git.
Slajd 36

Rebase działa poprzez pobranie commitów z bieżącej gałęzi i nałożenie ich na wierzch innej gałęzi (zwykle głównej). Każdy commit jest aplikowany jako nowy obiekt z nowym hashem, co sprawia, że historia wydaje się liniowa, jakby gałąź była tworzona od początku na aktualnej wersji głównej.

Główną zaletą rebase jest czysta, czytelna historia bez zbędnych rozwidleń. Wadą jest zmiana historii: jeśli ktoś już pracował na oryginalnych commitach, rebase tworzy ich duplikaty, co może prowadzić do chaosu. Dlatego rebase stosuje się tylko do lokalnych, nieopublikowanych zmian.

37/50
Złota zasada rebase: Nigdy nie wypychaj!
  • Rebase zmienia historię (kasuje stare zatwierdzenia i tworzy nowe).
  • NIGDY nie używaj rebase na gałęziach, które wysłałeś już na serwer (push) i widzą je inni.
  • Może to wywołać całkowity chaos u Twoich kolegów i koleżanek z zespołu.
  • Etyka pracy z Gitem wymaga odpowiedzialności za wspólną linię czasu.
  • Rebase jest świetny lokalnie, ale bywa niszczycielski globalnie.
  • Szacunek dla stabilności wspólnego kodu to podstawa zaufania w branży IT.
Slajd 37

Złota zasada rebase (The Golden Rule of Rebase) brzmi: nigdy nie rebaseuj commitów, które zostały wypchnięte na wspólne repozytorium i są widoczne dla innych członków zespołu. Naruszenie tej zasady może prowadzić do duplikacji commitów, konfliktów i utraty pracy innych osób.

Jeśli przypadkowo wykonasz rebase na opublikowanych commitach i wypchniesz zmiany (push --force), inni członkowie zespołu będą mieli trudności z synchronizacją. W takiej sytuacji najlepiej jak najszybciej poinformować zespół i wspólnie przywrócić poprzedni stan repozytorium z refloga.

38/50
Interaktywny Rebase: Redagowanie przeszłości
  • Chcesz połączyć małe zatwierdzenia w jeden większy? Zmienić ich kolejność?
  • `git rebase -i` to edytor historii, który daje chirurgiczną precyzję.
  • Możesz użyć poleceń `pick`, `squash` czy `edit`, by dopracować swój wkład.
  • Dzięki temu prezentujesz swoją pracę jako spójną i logiczną całość.
  • Pozwala to uniknąć splotów w stylu "poprawka literówki" powtarzających się 10 razy.
  • To narzędzie dla profesjonalistów, którzy dbają o najwyższą jakość zapisu.
Slajd 38

Interaktywny rebase (git rebase -i) otwiera edytor z listą commitów, które mają zostać zmodyfikowane. Dla każdego commita możesz wybrać akcję: pick (zostaw), reword (zmień opis), edit (edytuj treść), squash (połącz z poprzednim), fixup (połącz, odrzucając opis) lub drop (usuń).

To narzędzie jest szczególnie przydatne przed wysłaniem pull requesta. Możesz połączyć kilka drobnych commitów (squash), poprawić ich opisy (reword) lub zmienić kolejność, aby historia była logiczna i czytelna. Pamiętaj jednak, że działa to tylko na lokalnych, nieopublikowanych commitach.

39/50
Komenda git stash: Chwilowe odkładanie pracy
  • Musisz natychmiast naprawić błąd na innej gałęzi, a Twój kod nie jest gotowy?
  • Użyj "schowka" (`git stash`), aby bezpiecznie przechować niezapisane zmiany.
  • Twój folder roboczy stanie się czysty, pozwalając na szybką zmianę zadania.
  • To "pauza" dla Twojej pracy, która chroni postępy przed utratą.
  • Gwarantuje płynność pracy dewelopera w dynamicznym środowisku.
  • Żaden postęp nie zostanie zmarnowany przez nagłe przerwanie kontekstu.
Slajd 39

git stash to mechanizm tymczasowego przechowywania zmian, które nie są jeszcze gotowe do zatwierdzenia. Stash tworzy tymczasowe obiekty w .git/refs/stash i przywraca folder roboczy do stanu czystego, umożliwiając przełączenie się na inną gałąź.

Domyślnie git stash przechowuje tylko śledzone pliki (tracked). Aby dodać także nieśledzone pliki, użyj git stash -u (--include-untracked) lub git stash -a (--all) dla absolutnie wszystkich plików. Schowek działa jak stos - możesz mieć wiele zapisanych stanów i przywracać je w dowolnej kolejności.

40/50
Zarządzanie schowkiem: apply i pop
  • Gdy wrócisz do swojego zadania, możesz łatwo „wyjąć" kod ze schowka.
  • Komenda `git stash pop` przywraca zmiany i usuwa wpis ze spisu schowanych prac.
  • `git stash apply` przywraca kod, ale zostawia kopię w schowku na wszelki wypadek.
  • To mechanizm, który zarządza Twoim postępem równie sprawnie, co historią zatwierdzeń.
  • Zapewnia bezpieczeństwo operacyjne i elastyczność w codziennych zadaniach.
  • Zrozumienie schowka to oszczędność nerwów i czasu każdego profesjonalisty.
Slajd 40

git stash pop przywraca ostatni zapisany stan ze schowka i usuwa go ze stosu. To najczęściej używana forma przywracania. git stash apply działa podobnie, ale pozostawia wpis w schowku, co jest przydatne, gdy chcesz zastosować te same zmiany w wielu miejscach.

Możesz zarządzać wieloma wpisami w schowku za pomocą git stash list (wyświetlenie listy), git stash show (podgląd zmian) i git stash drop (usunięcie konkretnego wpisu). Każdy wpis ma identyfikator stash@{0}, stash@{1} itd., gdzie 0 to najnowszy wpis.

41/50
Pojęcie Upstream: Połączenie z chmurą
  • Każda lokalna gałąź może śledzić swój odpowiednik na serwerze (np. na GitHub).
  • Upstream (źródło) to relacja, która pozwala na proste używanie komend `push` i `pull`.
  • Git wie, skąd pobierać nowości i gdzie wysyłać Twoje poprawki.
  • Zapewnia doskonałą symetrię między Twoim komputerem a światową siecią.
  • To most, dzięki któremu projekty rozwijane na wielu kontynentach zostają spójne.
  • Dzięki niemu wiesz dokładnie, czy Twój kod jest aktualny względem "prawdy" w chmurze.
Slajd 41

Upstream (gałąź źródłowa) to relacja między lokalną gałęzią a jej odpowiednikiem na zdalnym serwerze. Ustawienie upstream pozwala na używanie samych komend git push i git pull bez podawania nazwy zdalnego repozytorium i gałęzi.

Upstream ustawia się podczas pierwszego pusha za pomocą git push -u origin <gałąź> lub później za pomocą git branch -u origin/<gałąź>. Git zapisuje tę konfigurację w pliku .git/config. Dzięki temu wiesz, z którą gałęzią zdalną pracujesz i skąd pobierać aktualizacje.

42/50
Squash Merging: Upraszczanie historii
  • Czasem gałąź ma 20 drobnych zatwierdzeń, które nie muszą zostać w historii na zawsze.
  • Squash Merging pozwala „zgniatać" wiele zatwierdzeń w jeden, czytelny i atomowy wpis.
  • Upraszcza to główną linię czasu, ułatwiając przyszłe czytanie dziennika zmian.
  • Zapewnia najwyższą jakość „produktu" końcowego w formie czystej historii.
  • To technika dbająca o profesjonalizm i wysoką przejrzystość całego projektu.
  • Mniej szumu oznacza większą czytelność dla każdego, kto dołączy do zespołu.
Slajd 42

Squash merging to technika scalania, w której wszystkie commity z gałęzi źródłowej są łączone w jeden commit na gałęzi docelowej. Różni się to od zwykłego merge, który zachowuje wszystkie oryginalne commity, i od rebase, który aplikuje je pojedynczo.

Główną zaletą squash merging jest czysta historia: zamiast 20 drobnych commitów (poprawka1, fix, dalsze prace, kolejna poprawka) pojawia się jeden commit z czytelnym opisem całej funkcji. Wadą jest utrata szczegółowej historii, co może utrudnić przyszłe debugowanie.

43/50
Komenda git cherry-pick: Chirurgiczna precyzja
  • Czasem potrzebujesz jednej konkretnej zmiany z innej gałęzi, ale nie wszystkich.
  • `cherry-pick` (wybieranie wisienki) kopiuje tylko wybrane zatwierdzenie do Twojej gałęzi.
  • To precyzyjne narzędzie do „przerzucania" poprawek błędów między wersjami.
  • Wymaga celności, by uniknąć duplikatów i niepotrzebnego zamieszania.
  • Uczy świadomego dobierania wkładu do różnych linii wydawniczych oprogramowania.
  • Dzięki niemu jesteś panem sytuacji, decydującym o każdym bajcie nowej wersji.
Slajd 43

git cherry-pick kopiuje pojedynczy commit z jednej gałęzi do bieżącej pozycji HEAD. Różni się to od merge, które przenosi całą gałąź, i od rebase, które przenosi zakres commitów. cherry-pick jest precyzyjny jak skalpel - przenosisz dokładnie to, czego potrzebujesz.

Cherry-pick jest często używany do przenoszenia poprawek błędów (hotfix) z gałęzi głównej do gałęzi wydaniowych (release branches) lub odwrotnie. Każdy skopiowany commit otrzymuje nowy hash i nowy znacznik czasu, ale zachowuje oryginalnego autora i wiadomość.

44/50
Git LFS: Obsługa wielkich plików
  • Standardowy Git nie radzi sobie dobrze z plikami o rozmiarze wielu gigabajtów.
  • Git LFS (Large File Storage) zastępuje ciężkie pliki małymi wskaźnikami.
  • Dzięki temu repozytorium pozostaje lekkie i szybkie, a dane są w chmurze LFS.
  • To rozwiązanie dla projektów z modelami 3D, wideo czy dużymi zbiorami danych.
  • Równoważy potrzebę wersji z wydajnością pracy całego zespołu.
  • Pozwala Gitowi wejść w rejony zarezerwowane dla największych wyzwań IT.
Slajd 44

Git LFS (Large File Storage) to rozszerzenie Gita, które zastępuje duże pliki (binaria, modele 3D, wideo, archiwa) małymi wskaźnikami tekstowymi w repozytorium, a rzeczywistą zawartość przechowuje na zewnętrznym serwerze (LFS server). Dzięki temu repozytorium pozostaje lekkie.

Podczas klonowania repozytorium z LFS pobierane są tylko wskaźniki, a rzeczywiste pliki są ściągane na żądanie (lazy loading) podczas git checkout. To znacznie przyspiesza klonowanie i oszczędza miejsce na dysku. GitHub oferuje darmowy limit 10 GB przestrzeni LFS (dla kont Free/Pro), a dodatkowa przestrzeń jest płatna.

45/50
Tagowanie: Oznaczanie kamieni milowych
  • Tag to pieczątka (np. v2.1.0) przypięta na stałe do konkretnego momentu w czasie.
  • W przeciwieństwie do gałęzi, tag się nie porusza - to historyczny pomnik.
  • Służy do oznaczania oficjalnych wydań (Releases) Twojego oprogramowania.
  • Pozwala użytkownikom łatwo pobrać stabilną wersję, nad którą pracowałeś.
  • Gesty taggingu budują profesjonalny wizerunek cyklu życia produktu.
  • Dzięki tagom każdy etap Twojej pracy zyskuje trwałą tabliczkę znamionową.
Slajd 45

Tagi w Gicie są stałymi wskaźnikami do konkretnych commitów, w przeciwieństwie do gałęzi, które się przesuwają. Tag lekkich (lightweight) to zwykły plik z hashem, a tag adnotowany (annotated) zawiera dodatkowo metadane: autora, datę i wiadomość.

Tagi adnotowane są zalecane do oznaczania oficjalnych wydań (release), ponieważ przechowują informację o tym, kto, kiedy i dlaczego utworzył dane wydanie. Tagi lekkie są używane raczej do tymczasowych oznaczeń. Tagi wypycha się na serwer osobno: git push --tags.

46/50
Submoduły: Zarządzanie zależnościami
  • Twój projekt korzysta z innego repozytorium jako części składowej?
  • Submoduły pozwalają zagnieździć jedno repozytorium wewnątrz drugiego.
  • Zapewnia to separację bibliotek i łatwe aktualizowanie zewnętrznych komponentów.
  • To standard korporacyjny przy budowaniu złożonych, modularnych systemów.
  • Dba o to, by każda część projektu miała własną, jasną wersjonowalność.
  • Inżynieria dużej skali nie mogłaby istnieć bez tak sprawnego podziału pracy.
Slajd 46

Submoduły (git submodule) pozwalają na dołączenie jednego repozytorium Gita jako podkatalogu w innym repozytorium. Każdy submoduł wskazuje na konkretny commit w zewnętrznym repozytorium, co zapewnia reprodukowalność - wiesz dokładnie, która wersja zależności jest używana.

Zarządzanie submodułami wymaga dodatkowych komend: git submodule update --init --recursive po klonowaniu nadrzędnego repozytorium. W praktyce submoduły bywają uciążliwe, dlatego w nowszych projektach często zastępuje się je menedżerami pakietów (npm, cargo, maven) lub narzędziami typu git subtree.

47/50
Komenda git bisect: Detektyw w kodzie
  • Wiesz, że program działał wczoraj, ale dziś ma błąd? Gdzie on powstał?
  • `git bisect` wykonuje przeszukiwanie binarne Twojej historii, by znaleźć sprawcę.
  • Automatycznie sprawdza zatwierdzenia między wersją „dobrą" a „złą".
  • To najszybszy sposób na śledzenie regresji w dużych projektach IT.
  • Uczy wykorzystywania historii jako aktywnego narzędzia do debugowania.
  • Dzięki detektywistycznej pracy z Gitem żadna usterka nie pozostanie w ukryciu.
Slajd 47

git bisect to narzędzie do binarnego przeszukiwania historii w celu znalezienia commita, który wprowadził błąd. Proces rozpoczyna się od oznaczenia commita jako dobry (git bisect good) i złego (git bisect bad). Git następnie dzieli historię na pół i prosi o przetestowanie kolejnych commitów.

Algorytm binarny gwarantuje, że przy N commitach potrzebujesz tylko log2(N) testów, aby znaleźć winowajcę. Dla 1000 commitów to zaledwie 10 testów. Możesz zautomatyzować bisect za pomocą git bisect run <skrypt>, który uruchamia skrypt testujący na każdym kandydacie.

48/50
Git Hooks: Automatyzacja lokalnych kontroli
  • Chcesz, by Git sprawdzał składnię Twojego kodu przed każdym commitem?
  • Hooki to skrypty, które uruchamiają się automatycznie przy określonych akcjach.
  • Mogą blokować push, jeśli testy nie przechodzą lub opis jest zbyt krótki.
  • Zapewniają wysoką jakość pracy jeszcze przed wysłaniem jej do chmury.
  • To Twoi cyfrowi asystenci, którzy pilnują Twojej produktywności i standardów.
  • Automatyzacja to kolejny krok w kierunku dojrzałości zawodowej w IT.
Slajd 48

Hooki (git hooks) to skrypty umieszczone w katalogu .git/hooks/, które są automatycznie uruchamiane przy określonych zdarzeniach. Przykłady: pre-commit (przed zatwierdzeniem), commit-msg (sprawdza wiadomość commita), pre-push (przed wypchnięciem) i post-merge (po scaleniu).

Hooki mogą być pisane w dowolnym języku (bash, Python, Perl). Są one lokalne dla każdego repozytorium i nie są wypychane na serwer. Aby udostępnić hooki zespołowi, przechowuje się je w osobnym katalogu (np. .githooks/) i konfiguruje git config core.hooksPath .githooks.

49/50
Aliasy i motywy: Personalizacja narzędzia
  • Nie chcesz wpisywać długich komend? Skróć je za pomocą aliasów.
  • `git co` zamiast checkout, `git s` zamiast status - to oszczędność cennego czasu.
  • Git pozwala dopasować kolory i zachowanie do Twoich unikalnych potrzeb.
  • Era profesjonalisty zaczyna się tam, gdzie narzędzie staje się przedłużeniem myśli.
  • Zoptymalizuj swój warsztat, by pracować szybciej i z większą przyjemnością.
  • Twoje środowisko pracy to Twoje królestwo - dbaj o jego ergonomię.
Slajd 49

Aliasy w Gicie to skróty dla często używanych komend. Definiuje się je w pliku konfiguracyjnym .gitconfig za pomocą sekcji [alias]. Przykładowo: co = checkout, s = status, l = log --oneline --graph, last = log -1 HEAD. Dobrze dobrane aliasy znacząco przyspieszają codzienną pracę.

Możesz także definiować aliasy wykonujące zewnętrzne polecenia, poprzedzając je wykrzyknikiem (!). Na przykład: git review = !sh -c 'git log --oneline origin/main..HEAD' wyświetli listę commitów do przesłania w pull requeście. Personalizacja Gita to cecha zaawansowanych użytkowników.

50/50
Podsumowanie wykładu: Droga do mistrzostwa
  • Opanowałeś mechanikę wewnętrzną, system gałęzi i techniki zaawansowane.
  • Przeszedłeś drogę od zwykłego użytkownika do architekta historii kodu.
  • Znasz zasady integralności, magię haszowania i siłę równoległego rozwoju.
  • To solidny fundament pod Twoją karierę w nowoczesnym przemyśle IT.
  • Pamiętaj: mistrzostwo osiąga się przez praktykę. Twórz, scalaj i nie bój się błędów.
  • Gratulacje! Jesteś gotowy na największe wyzwania w globalnej społeczności deweloperów.
Slajd 50

W trakcie tego wykładu przeszedłeś kompleksową drogę od wewnętrznych mechanizmów Gita, przez system gałęzi, aż po zaawansowane techniki, takie jak rebase, cherry-pick i bisect. Zdobyta wiedza stanowi solidny fundament pod samodzielną pracę z kodem w profesjonalnym środowisku IT.

Pamiętaj, że Git to narzędzie, które wymaga praktyki. Nie bój się eksperymentować - zakładaj gałęzie, scalaj je, rozwiązuj konflikty. Każdy błąd to lekcja, a reflog daje ci bezpieczną siatkę asekuracyjną. Im więcej praktyki, tym bardziej naturalne staną się zaawansowane operacje. Powodzenia w dalszej drodze do mistrzostwa!