Przejdź do treści

Git: podstawy

Git zapisuje historię zmian w projekcie. Możemy sprawdzić, co się zmieniło, wybrać zmiany do zapisania, a później wrócić do wcześniejszej wersji. Repozytorium Git działa lokalnie, więc do tej lekcji nie potrzebujemy GitHuba ani połączenia ze zdalnym serwerem.

Repozytorium

Repozytorium to katalog projektu wraz z historią zmian. Git przechowuje tę historię w ukrytym katalogu .git/.

W katalogu projektu tworzymy repozytorium z główną gałęzią main:

git init -b main

Jeśli używana wersja Git nie obsługuje -b, wykonaj git init, a potem zmień nazwę bieżącej gałęzi:

git branch -M main

Git musi wiedzieć, kto tworzy commity. To ustawienie można zapisać raz dla wszystkich repozytoriów:

git config --global user.name "Jan Kowalski"
git config --global user.email "jan@example.org"

Można też ustawić nazwę i adres tylko w bieżącym repozytorium, pomijając --global. Wtedy trzeba wykonać polecenia wewnątrz repozytorium.

Trzy miejsca na zmiany

Git rozróżnia katalog roboczy, poczekalnię (ang. staging area lub index) i historię repozytorium:

Miejsce Co zawiera
katalog roboczy bieżące pliki, które edytujemy
poczekalnia zmiany wybrane do następnego commitu
repozytorium zapisane commity i ich historia

Typowa droga zmiany wygląda tak:

katalog roboczy  --git add-->  poczekalnia  --git commit-->  historia

Commit jest zapisem wybranych zmian. Zawiera autora, datę, opis i odwołanie do poprzedniego commitu. Git identyfikuje go unikalnym skrótem.

Sprawdzanie stanu

Najczęściej zaczynamy od git status. Pokazuje, na jakiej gałęzi pracujemy i które pliki są nowe, zmienione albo przygotowane do commitu.

git status

Polecenie git diff pokazuje niezapisane zmiany w katalogu roboczym. Po dodaniu pliku do poczekalni można sprawdzić, co trafi do następnego commitu:

git diff
git diff --staged

Warto uruchomić git status i obejrzeć różnice przed każdym commitem.

Dodawanie zmian i commity

git add dodaje plik do poczekalni. git commit zapisuje zmiany z poczekalni jako nowy punkt w historii.

git add README.md src/main.c
git diff --staged
git commit -m "Add station status output"

Możemy dodać tylko wybrane pliki. Dzięki temu jeden commit może zawierać zmianę w dokumentacji, a kolejny niezależną zmianę w kodzie.

Opisy commitów powinny krótko mówić, co zmiana robi, np. Ignore build output albo Add radio link status. Unikaj opisów, które nic nie wyjaśniają, takich jak changes lub fix.

Pierwszy commit często zapisuje początkową wersję projektu:

git add README.md Makefile src/main.c config/station.conf
git commit -m "Add station monitor project"

Oglądanie historii

git log pokazuje historię commitów. Przydatne opcje:

git log --oneline
git log --oneline --graph --all
git show <commit>

--oneline skraca wpisy, a --graph --all pokazuje historię wszystkich gałęzi. git show wyświetla zmiany zapisane w wybranym commicie. Można podać jego skrót albo użyć HEAD, które oznacza bieżący commit.

Pliki, których nie chcemy śledzić

Programy i pliki obiektowe są generowane podczas budowania projektu. Zwykle nie dodajemy ich do repozytorium. Lista reguł .gitignore mówi Gitowi, które nieśledzone pliki ma pomijać:

/build/
*.o

Po zapisaniu .gitignore sprawdź:

git status
git check-ignore -v build/station

Reguła ignorowania nie przestaje śledzić pliku, który wcześniej dodano do repozytorium. Taki plik trzeba najpierw usunąć z poczekalni z opcją --cached, np. git rm --cached build/station.

Cofanie zmian przed commitem

Możemy wycofać plik z poczekalni, zachowując jego edycję w katalogu roboczym:

git restore --staged README.md

Polecenie git restore README.md przywraca plik z ostatniego commitu. Usuwa więc niezapisane edycje tego pliku. Przed jego użyciem sprawdź nazwę pliku i git status.

Gałęzie

Gałąź (ang. branch) to lekki wskaźnik na commit. Pozwala rozwijać zmianę osobno, bez mieszania jej od razu z pracą na main.

git switch -c feature/heartbeat
# edytuj pliki, git add, git commit
git switch main

git switch -c tworzy gałąź i od razu się na nią przełącza. git branch wyświetla gałęzie; gwiazdka oznacza bieżącą gałąź.

Łączenie gałęzi

Po zakończeniu pracy na gałęzi możemy połączyć ją z main:

git switch main
git merge feature/heartbeat

Jeżeli gałęzie zmieniły różne fragmenty projektu, Git zwykle połączy je automatycznie. Po merge sprawdź git status i obejrzyj historię:

git status
git log --oneline --graph --all

Konflikty merge

Konflikt pojawia się podczas łączenia gałęzi, gdy obie zmieniły ten sam fragment pliku w różny sposób. Git wstawia wtedy do pliku znaczniki podobne do tych:

<<<<<<< HEAD
uplink=offline
=======
uplink=online
>>>>>>> station-update

HEAD oznacza wersję z bieżącej gałęzi, a druga część pochodzi z gałęzi, którą łączymy. Otwórz plik, wybierz poprawną treść i usuń wszystkie znaczniki. Następnie dodaj rozwiązany plik do poczekalni i zakończ merge commitem:

git add config/station.conf
git commit

Po rozwiązaniu konfliktu sprawdź, czy w git status nie ma już nierozwiązanych plików i czy wynikowa treść jest poprawna. Konflikt nie oznacza, że commit się nie udał — dwa osobne commity mogą powstać bez problemu; konflikt jest zgłaszany przy ich łączeniu.

Typowy cykl pracy

git status
# edytuj plik
git diff
git add <plik>
git diff --staged
git commit -m "Describe the change"
git status

Przed commitem sprawdzamy, co dodamy. Po nim sprawdzamy, czy katalog roboczy jest w oczekiwanym stanie.