Większość programistów używa Gita jak czarnej skrzynki: coś wpisujesz, coś się zapisuje, historia jakoś działa. Dopóki coś nie pójdzie nie tak. Żeby Git przestał być magią – zacznij od zrozumienia, co naprawdę siedzi w katalogu .git/. Cztery typy obiektów: blob, tree, commit, tag. Tyle. Reszta to konsekwencje.
Cztery typy obiektów
Git to baza danych obiektów adresowanych zawartością. Każdy obiekt identyfikowany jest przez SHA-1 swojej zawartości. Zmień jeden bajt – zmienia się SHA.
Blob
Blob przechowuje surową zawartość pliku. Nie zna nazwy ani ścieżki – to zadanie tree. Dwa identyczne pliki w różnych katalogach to jeden blob.
echo "Hello, Git" | git hash-object --stdin # 8ab686eafeb1f44702738c8b0f24f2567c36da6d git cat-file -p 8ab686eafeb1f44702738c8b0f24f2567c36da6d # Hello, Git
Tree
Tree to lista wpisów: tryb pliku, typ (blob lub tree), SHA i nazwa. Odpowiednik katalogu w systemie plików.
git cat-file -p HEAD^{tree}
# 100644 blob a8a940627d13... README.md
# 100644 blob 1f7391f9274f... composer.json
# 040000 tree 2a1bcad13f8e... src
Commit
Commit wskazuje na jeden tree (korzeń repozytorium), na zero lub więcej commitów-rodziców, i zawiera autora, commiter, timestamp i wiadomość.
git cat-file -p HEAD # tree 2a1bcad13f8e8c8d9d2b7d6c4f2a1e9b8c7d6e5f # parent a3d5e2f1b4c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0 # author Henryk Tews <henryk@tews.pl> 1746531600 +0200 # committer Henryk Tews <henryk@tews.pl> 1746531600 +0200 # # Add product export service
Tag
Annotated tag to osobny obiekt wskazujący na inny obiekt (zwykle commit). Lekki tag to tylko ref – plik w .git/refs/tags/ zawierający SHA.
Referencje – ludzkie nazwy dla SHA
SHA jak a3d5e2f1b4c6 jest precyzyjne, ale niepraktyczne. Referencje to pliki tekstowe zawierające SHA.
cat .git/refs/heads/main # a3d5e2f1b4c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0 cat .git/HEAD # ref: refs/heads/main <- attached HEAD (wskazuje na branch) # lub: # a3d5e2f1b4c6... <- detached HEAD (wskazuje na commit)
Co z tego wynika praktycznie
Branch to jeden plik z SHA. Tworzenie brancha jest tanie jak zapis jednego pliku. Merge to stworzenie nowego commita z dwoma rodzicami.
Git przechowuje migawki, nie różnice. Każdy commit to pełny obraz - tree wskazujące na wszystkie blobs. Różnice obliczane są na bieżąco. Blobs współdzielone między commitami nie są duplikowane - to efekt adresowania zawartością.
SHA nigdy nie kłamie. Jeśli dwa SHA są identyczne, zawartość jest identyczna. To fundament integralności Gita.
Struktura .git/
.git/
├── HEAD # gdzie jesteś teraz
├── config # konfiguracja repozytorium
├── index # staging area (binarne)
├── objects/ # baza danych obiektów
│ ├── aa/ # pierwsze 2 znaki SHA = podkatalog
│ │ └── 3f...
│ └── pack/ # spakowane obiekty
└── refs/
├── heads/ # lokalne branche
├── remotes/ # referencje zdalne
└── tags/
Polecenia do eksploracji
# Typ obiektu git cat-file -t SHA # Zawartość obiektu git cat-file -p SHA # Graficzne drzewo commitów git log --oneline --graph --all # Wszystkie pliki w HEAD git ls-tree -r HEAD
Podsumowanie
Git to cztery typy obiektów plus referencje. Zrozumienie tej struktury wyjaśnia zachowania wyglądające jak magia: dlaczego branche są tanie, dlaczego rebase przepisuje SHA, dlaczego dwa identyczne pliki zajmują tyle samo miejsca co jeden. Następny wpis: commity i historia - dobre wiadomości commitów, rebase -i, cherry-pick i bisect.
