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.

Ważne!

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.

Ważne!

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.

Ważne!

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 mainbranch.

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ę.

Przykład 1

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:

  1. Odrzucić zmiany w repozytorium, zaproponowane przez użytkownika „B”.

  2. Przyjąć wersję „B” za właściwą.

  3. 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ć.

Ważne!

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 IDEIDEIDE nie udostępnia opcji inteligentnego wyszukiwaniainteligentne wyszukiwanieinteligentnego 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 konsolikonsola systemowakonsoli.

Ważne!

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 StudioPyCharm itd., posiada wbudowaną obsługę repozytoriów. Jest to dla programistów udogodnienie, bez którego nie wyobrażają sobie pracy.

Dla zainteresowanych

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

IDE
IDE

(ang. Integrated Development Environment) zintegrowane środowisko programistyczne; najczęściej zawiera edytor kodu źródłowego oraz wbudowany kompilator lub interpreter

inteligentne wyszukiwanie
inteligentne wyszukiwanie

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

konsola systemowa
konsola systemowa

aplikacja systemu operacyjnego, pozwalająca na pracę z wykorzystaniem poleceń i komend