Przeczytaj
Definicja repozytorium
Pojęcie „repozytorium” wywodzi się z języka łacińskiego, a jego pierwotne znaczenie nie ma związku z informatyką. Oznacza uporządkowane miejsce służące do przechowania dokumentów, które przeznaczone są do upublicznienia.
Takie repozytoria są udostępniane m.in. przez instytucje naukowe, można w nich zapoznać się ze zweryfikowanymi pracami bądź z artykułami naukowymi. Przykładem jest repozytorium Politechniki Warszawskiej. Można tam uzyskać dostęp do ponad 90 tys. publikacji, 70 tys. prac naukowych, 12 tys. projektów i 4 tys. prac doktorskich (dane z początku 2021 r.).
Repozytorium w informatyce
W informatyce najpopularniejszym rodzajem repozytorium jest repozytorium Git, które jest systemem kontroli wersji.
Dzięki temu oprogramowaniu możemy sprawdzać obecny oraz archiwalny stan kodu źródłowego. Ponadto zawiera ono narzędzia ułatwiające pracę nad danym kodem źródłowym. Wiele serwisów hostingowych wykorzystujących system kontroli wersji Git – jak omawiany GitHub – ma wbudowaną wiki, system kontroli widoczności danego projektu oraz kontrolę uprawnień użytkownika.
GitHub może być wykorzystywany komercyjnie do pracy grupowej nad kodem źródłowym, do którego w takim wypadku mają dostęp jedynie wybrane osoby. W serwisie znajduje się również mnóstwo projektów open source, w których społeczność tworzy oraz utrzymuje kod.
Generalna zasada działania
System kontroli wersji Git działa na dwóch płaszczyznach. Po pierwsze umożliwia kontrolę wersji na komputerze lokalnym. Oznacza to, że nie musimy aktualizować wszystkich wprowadzanych przez nas zmian od razu do sieci bądź chmury. Wersja repozytorium zapisana lokalnie może różnić się od tej głównej, przyjętej w całym systemie.
Drugą płaszczyzną jest właśnie warstwa sieciowa samego systemu. Jak już wspominaliśmy, zmiany nie są natychmiastowo wgrywane do systemu. Dodatkowo ten sam fragment kodu może być modyfikowany jednocześnie na wielu komputerach. W sytuacji, gdy dwa repozytoria lokalne próbują nadpisać w tym samym momencie wersję główną tego samego fragmentu kodu – dochodzi do konfliktów. System umożliwia rozwiązywanie tego typu problemów.
Wersje kodu
Główna wersja kodu zazwyczaj nosi nazwę master
. Wersję lokalną repozytorium nazywamy local
(ang. lokalny), a wersję będącą w chmurze, jak np. w serwisie GitHub, określamy remote
(ang. zdalny, odległy, oddalony).
Musimy jednak dodać, że każde repozytorium lokalne ma swoją własną wersję nazywaną master
, lub main
zależnie od przyjętej w danym repozytorium konwencji. Programista najpierw uaktualnia swoją wersję master
w lokalnym repozytorium (wersja local
), a następnie może na tej podstawie zaktualizować wersję master
na remote
.
Wspomnieliśmy przed chwilą, że główna wersja kodu zazwyczaj nosi nazwę master
. Warto jednak wiedzieć, że główną wersję kodu można nazwać w dowolny sposób.
Polecenia Git
Omówmy kluczowe polecenia systemu kontroli wersji Git. Zacznijmy od najbardziej podstawowego – polecenia commit
. Powoduje ono, że zmiany są zapisywane w wersji master
w lokalnym repozytorium. Nie powoduje ono jednak zmian w wersji remote
.
W środowisku programistycznym często pojedynczy wynik użycia polecenia commit
określany jest mianem commit
.
Zanim przejdziemy dalej, warto omówić pojęcie branch
(ang. gałąź, odnoga). Określamy w ten sposób ustaloną wersję kodu o zadanej nazwie. Master
to właśnie najczęściej główny branch
, od którego odchodzą wszystkie inne nowo utworzone wersje.
Branch
pozwala nam stworzyć kopię naszego kodu, a następnie zapisywać w niej zmiany, bez nadpisywania oryginału. Załóżmy, że pracujemy przy przywoływanym we wcześniejszych e‑materiałach projekcie gry Snake. W nim tworzymy branch
„ruch ogona”. Stosujemy polecenie commit
regularnie, dzięki czemu zapisujemy zmiany w lokalnym repozytorium.
Wyobraźmy sobie sytuację, w której orientujemy się, że w trakcie pracy popełniliśmy błędy. Jeśli zapisywaliśmy zmiany na wersji master
, mamy zły kod w archiwum.
Niechciane zmiany możemy wycofać za pomocą polecenia revert
. Nie należy ono do „podstawowego” zbioru poleceń. Tak naprawdę jest to polecenie commit
, które polega na usunięciu wszelkich zmian wprowadzonych przez nas za pomocą danego commit
.
W sytuacji, w której zmiany zapisywaliśmy na oddzielnej wersji branch
, wystarczy, że ją skasujemy, bądź po prostu przestaniemy na niej pracować i wrócimy do wersji master
. Najrozsądniej byłoby utworzyć nową wersję branch
, na której będziemy wprowadzać kolejne poprawki.
Tworzenie nowych wersji branch
na każdą zmianę nie jest technicznie wymagane, jednakże w większych projektach mile widziane. Uznaje się, że master
to wersja kodu, którą w razie potrzeby się kompiluje. Wyobraźmy sobie sytuację, w której pracując w dużej firmie przy ważnym projekcie, wprowadzamy przy pomocy polecenia commit
bezpośrednio zmiany w wersji master
. Jeśli popełnimy błąd, może on potencjalnie skutkować ogromnymi stratami finansowymi. Ten sam błąd mógłby zostać wychwycony w procesie weryfikacji podczas aktualizowania wersji main
z branch
.
Operacja scalania
Proces łączenia dwóch różnych wersji branch
określamy mianem merge
(ang. złączenie, scalenie). Wszystkie zmiany wprowadzone w danej wersji branch
, po wykonaniu operacji scalania są wgrywane do wersji main
, inaczej mówiąc – nasze commity
pojawiają się w wersji branch
o nazwie main
.
Można oczywiście tworzyć kolejne wersje branch
i scalać za pomocą merge
dwie dowolnie wybrane z nich, jednak należy przy tym zachować rozwagę.
Wyobraźmy sobie sytuację, w której użytkownik „A” tworzy commit
o nazwie UpdateA
. Następnie użytkownik „B” tworzy swój commit
o nazwie UpdateB
. Obydwaj pracowali na tej samej wersji repozytorium, ale w efekcie mają różniące się od siebie repozytoria lokalne.
Następnie próbują wykonać polecenie push
(ang. pchnij). Służy ono do wgrania i zatwierdzenia zmian wprowadzonych lokalnie do wersji remote
, umieszczonej na zdalnym serwerze. Załóżmy, że „A” wgrywa swoją zmianę pierwszy, wszystko udaje się bezproblemowo, repozytorium zdalne zostało zaktualizowane. Jednakże teraz „B” próbuje wgrać swoją zmianę i dochodzi do konfliktu.
Należy tutaj dodać, że konflikt pojawia się tylko w sytuacji, w której programiści edytują te same linijki. Gdyby użytkownik „A” pracował na plikach, których nazwy zaczynają się od litery „t”, a „B” edytował te zaczynające się od litery „a”, to do konfliktu by nie doszło, a obie wersje uzupełniałyby się.
System kontroli nie jest w stanie sam poradzić sobie z problemem opisanym w Przykładzie 1. Konflikt tego rodzaju można rozwiązać na trzy sposoby:
Odrzucić zmiany w repozytorium, zaproponowane przez użytkownika „B”.
Przyjąć wersję „B” za właściwą.
Ręcznie edytować plik.
Najbardziej pożądana jest trzecia opcja. W praktyce polega ona na otwarciu pliku, w którym występuje konflikt i ręcznej edycji. Przykładowo program GitHub Desktop radzi sobie z tego typu problemami w ten sposób, że do pliku, w którym wystąpił konflikt, w odpowiednim miejscu wkleja obie wersję kodu. Plik taki można wtedy otworzyć i edytować.
Stosowanie zasady „jeden branch
, jedna funkcjonalność” pozwala unikać konfliktów podczas operacji scalania wersji.
Pozostały nam do omówienia trzy polecenia: fetch
, pull
oraz clone
.
Polecenie fetch
ściąga wersję kodu z remote
na local
, jest to więc odwrotność polecenia push
, jednakże nie integruje ściągniętych danych z repozytorium.
Integracją ściągniętych danych zajmuje się natomiast polecenie pull
, które – co warto zaznaczyć – ściąga również aktualizacje z chmury.
Polecenie clone
służy do ściągnięcia kodu całkowicie. Używa się go najczęściej, gdy już istnieje repozytorium zdalne, które chcemy skopiować jako repozytorium lokalne.
Serwis GitHub
Serwis ten jest ogólnodostępny oraz darmowy. W jednym z poprzednich e‑materiałów omawialiśmy znajdujące się tam wiki, a także proces tworzenia nowego konta i projektu.
Serwis ten ma wbudowaną wyszukiwarkę. Możemy się nią posłużyć, żeby wyszukać w kodzie jakiejś frazy, np. w wypadku, w którym kod jest podzielony na wiele plików, a IDEIDE nie udostępnia opcji inteligentnego wyszukiwaniainteligentnego wyszukiwania. Poszukiwana fraza może być komentarzem lub fragmentem kodu, więc jeżeli szukamy zdefiniowanej przez nas metody, klasy lub atrybutu, jest to użyteczne rozwiązanie.
Dodatkowo sam GitHub posiada aplikację, która umożliwia zarządzanie repozytorium z poziomu interfejsu, zamiast z poziomu konsolikonsoli.
Warto w tym momencie dodać, że jednoczesne korzystanie z repozytorium z poziomu interfejsu graficznego oraz konsoli może powodować błędy. Dlatego zaleca się, żeby korzystać z jednej metody.
Wiele współczesnych IDE takich jak InteliJ, Visual Studio, PyCharm itd., posiada wbudowaną obsługę repozytoriów. Jest to dla programistów udogodnienie, bez którego nie wyobrażają sobie pracy.
W tym e‑materiale zostały omówione podstawowe polecenia i pojęcia, które są niezbędne do pracy z systemem Git.
Zachęcamy do samodzielnego zaznajomienia się z pozostałymi poleceniami, oraz z używaniem ich za pośrednictwem konsoli.
Słownik
(ang. Integrated Development Environment) zintegrowane środowisko programistyczne; najczęściej zawiera edytor kodu źródłowego oraz wbudowany kompilator lub interpreter
rozumiane jest jako znajdywanie informacji, których użytkownik oczekuje; przykładowo wpisanie w wyszukiwarkę Google frazy „błędne wyświetlanie się okna”, nie powinno pokazywać nam wyników związanych z hasłem „bezbłędne wyświetlanie się okna”, ponieważ nie są one tymi, których oczekujemy
aplikacja systemu operacyjnego, pozwalająca na pracę z wykorzystaniem poleceń i komend