Rozdział 3. Klonowanie

W starszych systemach kontroli wersji polecenie checkout stanowi standardową operację pozyskiwania danych. Otrzymasz nią zbiór plików konkretnej wersji.

W Git i innych rozproszonych systemach standardowo służy temu operacja clone. By pozyskać dane, tworzysz najpierw klon całego repozytorium. Lub inaczej mówiąc, otrzymujesz lustrzane odbicie serwera. Wszystko, co można zrobić w centralnym repozytorium, możesz również robić z klonem.

Synchronizacja komputera

W celu ochrony danych mógłbym jeszcze zaakceptować korzystanie z archiwum tar, a dla prostej synchronizacji używania rsync. Jednak czasami pracując na laptopie, a innym razem na komputerze stacjonarnym, może się zdarzyć, że komputery nie miały możliwości zsynchwonizowania się w międzyczasie.

Utwórz repozytorium Gita w wykonaj commit twoich danych na jednym z komputerów. Potem na następnym wpisz:

$ git clone drugi.komputer:/ścieżka/do/danych

by otrzymać drugą kopię danych i jednocześnie utworzyć repozytorium Gita na drugim komputerze. Od teraz poleceniem:

$ git commit -a

$ git pull drugi.komputer:/ścieżka/do/danych HEAD

przenosisz stan drugiego komputera na komputer na którym właśnie pracujesz. Jeśli dokonałaś zmian w tym samym pliku na obydwu komputerach, Git poinformuje cię o tym, po usunięciu konfliktu powinnaś ponowić commit.

Klasyczna kontrola kodu źródłowego

Utwórz repozytorium Gita w katalogu roboczym projektu:

$ git init
$ git add .
$ git commit -m "Pierwszy commit"

Na centralnym serwerze utwórz gołe (bare) repozytorium w jakimkolwiek katalogu:

$ mkdir proj.git
$ cd proj.git
$ git --bare init
$ touch proj.git/git-daemon-export-ok

W razie konieczności wystartuj daemon Gita:

$ git daemon --detach # ponieważ, gdyby uruchomiony był wcześniej

Jeśli korzystasz z hostingu to poszukaj na stronie usługodawcy wskazówek jak utworzyć repozytorium bare. Zwykle konieczne jest do tego wypełnienie formularza online na jego stronie.

Popchaj (push) twój projekt teraz na centralny serwer:

$ git push centralny.serwer/ścieżka/do/projektu.git HEAD

By pozyskać kod źródłowy programista podaje zwykle polecenie w rodzaju:

$ git clone główny.serwer/ścieżka/do/projektu.git

Po dokonaniu edycji programista zapamiętuje zmiany najpierw lokalnie:

$ git commit -a

Aby zaktualizować do wersji istniejącej na głównym serwerze:

$ git pull

Jeśli wystąpią jakiekolwiek konflikty łączenia (merge) , powinny być najpierw usunięte i na nowo zostać wykonany commit.

$ git commit -a

Lokalne zmiany przekazujemy do serwera poleceniem:

$ git push

Jeśli w międzyczasie nastąpiły nowe zmiany na serwerze wprowadzone przez innego programistę, twój push nie powiedzie się. Zaktualizuj lokalne repozytorium ponownie poleceniem pull, pozbądź się konfliktów i spróbuj jeszcze raz.

Programiści potrzebują dostępu poprzez SSH dla wykonania poleceń pull i push. Mimo to, każdy może skopiowć kod źródłowy poprzez podanie:

$ git clone git://główny.serwer/ścieżka/do/projektu.git

Protokół GIT przypomina HTTP: nie posiada uwierzytelniania, a więc każdy może skopiować dane. Przy ustawieniach standardowych wykonanie push za pomocą protokołu GIT jest zdezaktywowane.

Utajnienie źródła

Przy projektach Closed-Source wyklucz używanie poleceń takich jak clone i upewnij się, że nie został utworzony plik o nazwie git-daemon-export-ok. Wtedy repozytorium nie może już komunikować się poprzez protokół git, tylko posiadający dostęp przez SHH mogą widzieć dane. Jeśli wszystkie repozytoria są zamknięte, nie ma potrzeby startować daemona git, ponieważ cała komunikacja odbywa się wyłącznie za pomocą SSH.

Gołe repozytoria

Określenie: gołe (bare) repozytorium, powstało, ze względu na fakt, iż repozytorium to nie posiada katalogu roboczego. Posiada jedynie dane, które są zwykle schowane w podkatalogu .git. Innymi słowy: zarządza historią projektu, nie posiada jednak katalogu roboczego jakiejkolwiek wersji.

Repozytorium bare przejmuje rolę podobną do roli głównego serwera w scentralizowanych systemach kontroli wersji: dach twojego projektu. Programiści klonują twój projekt stamtąd i przesyłają tam ostatnie oficjalne zmiany. Często znajduje się ono na serwerze, którego jedynym zadaniem jest wyłącznie dystrybucja danych. Sama praca nad projektem przebiega na jego klonach, w ten sposób główne repozytorium daje sobie radę nie korzystając z katalogu roboczego.

Wiele z poleceń Gita nie będzie funkcjonować w repozytoriach bare, chyba że ustawimy zmienną systemową GIT_DIR na katalog roboczy repozytorium albo przekażemy opcję --bare.

Push, czy pull?

Dlaczego wprowadziliśmy polecenie push, a nie pozostaliśmy przy znanym nam już pull? Po pierwsze, pull nie działa z repozytoriami bare: zamiast niego używaj fetch, polecenia którym zajmiemy się później. Również gdybyśmy nawet używali normalnego repozytorium na serwerze centralnym, polecenie pull byłoby raczej niewygodne. Musielibyśmy wpierw zalogować się na serwerze i przekazać poleceniu pull adres IP komputera z którego chcemy ściągnąć pliki. Jeśli w ogóle posiadalibyśmy dostęp do konsoli serwera, to prawdopodobnie przeszkodziłaby nam firewalle na drodze do naszego komputera.

W każdym bądź razie, nawet jeśli nawet mogło by to zadziałać, odradzam z korzystania z funkcji push w ten sposób. Poprzez samo posiadanie katalogu roboczego na serwerze mogłoby powstać wiele nieścisłości.

Krótko mówiąc, podczas gdy uczysz się korzystania z Git, korzystaj z polecenia push tylko, gdy celem jest repozytorium bare, we wszystkich innych wypadkach z pull.

Rozwidlenie projektu

Jeśli nie potrafisz już patrzeć na kierunek rozwoju w jakim poszedł jakiś projekt. Uważasz, że potrafisz to lepiej. To po prostu utwórz jego fork, w tym celu na twoim serwerze podaj:

$ git clone git://główny.serwer/ścieżka/do/danych

Następnie, poinformuj wszystkich o nowym forku projektu na twoim serwerze.

W każdej późniejszej chwili możesz dokonać łączenia (merge) zmian z oryginalnego projektu, poprzez:

$ git pull

Ultymatywny backup

Chcesz posiadać liczne, wolne od manipulacji, redundantne kopie bezpieczeństwa w różnych miejscach? Jeśli projekt posiada wielu programistów, nie musisz niczego robić. Ponieważ każdy klon twojego kodu jest pełnowartościową kopią bezpieczeństwa. Nie tylko jego aktualna wersja, lecz również cała historia projektu. Gdy jakikolwiek klon zostanie uszkodzony, dzięki kryptograficznemu hashowaniu, zostanie to natychmiast rozpoznane, jeśli tylko dana osoba będzie próbować wymiany z innymi.

Jeśli twój projekt nie jest jeszcze wystarczająco znany, spróbuj pozyskać tak wiele serwerów, ile to możliwe, by umieścić tam jego klon.

Ci najbardziej paranoidalni powinni zawsze zapisywać 20 bajtów ostatniej sumy kontrolnej SHA1 dla HEAD i przechowywać w bezpiecznym miejscu. Musi być bezpieczny, jednak nie tajny. Na przykład opublikowanie go w gazecie dobrze by spełniło swoje zadanie, dość trudnym zadaniem byłoby zmanipulowanie każdej kopii gazety.

Wielozadaniowość z prędkością światła

Załóżmy, że chcesz pracować nad kilkoma funkcjami równocześnie. Wykonaj commit i wpisz:

$ git clone . /jakiś/nowy/katalog

Za sprawą twardych linków stworzenie lokalnej kopii zajmuje dużo mniej czasu i pamięci niż zwykły backup.

Możesz pracować nad dwoma niezależnymi funkcjami jednocześnie. Na przykład, możesz pracować nad jednym klonem dalej, podczas gdy drugi jest właśnie kompilowany. W każdym momencie możesz wykonać commit i pull innego klonu.

$ git pull /inny/klon HEAD

Kontrola wersji z podziemia

Pracujesz nad projektem, który używa innego systemu kontroli wersji i tęsknisz za Gitem? Utwórz po prostu repozytorium Gita w twoim katalogu roboczym:

$ git init
$ git add .
$ git commit -m "Pierwszy commit"

następnie sklonuj go:

$ git clone . /jakiś/inny/katalog

Przejdź teraz do nowego katalogu i pracuj według upodobania. Kiedyś zechcesz zsynchronizować pracę, idź do oryginalnego katalogu, zaktualizuj go najpierw z tym innym systemem kontroli wersji, następnie wpisz:

$ git add .
$ git add . $ git commit -m"Synchronizacja z innym systemem kontroli wersji"

Teraz przejdź do nowego katalogu i podaj:

$ git commit -a -m "Opis zmian"
$ git pull

Sposób w jaki przekażesz zmiany drugiemu systemowi zależy już od jego sposobu działania. Twój nowy katalog posiada dane ze zmianami przez ciebie wprowadzonymi. Wykonaj jeszcze adekwatne kroki żądane przez ten inny system kontroli wersji, by przekazać dane do centralnego repozytorium.

Subversion, być może najlepszy z centralnych systemów, stosowany jest w wielu projektach. Komenda git svn automatyzuje powyższe kroki, może być użyta na przykład do exportu projektu Git do repozytorium Subversion.

Mercurial

Mercurial to podobny do Gita system kontroli wersji, który prawie bezproblemowo potrafi pracować z Gitem. Korzystając z rozszerzenia hg-git użytkownik Mercurial jest w stanie bez strat wykonywać push i pull z repozytorium Gita.

Możesz ściągnąć sobie rozszerzenie hg-git za pomocą Gita:

$ git clone git://github.com/schacon/hg-git.git

albo za pomocą Mercurial:

$ hg clone http://bitbucket.org/durin42/hg-git/

Niestety nie są mi znane takie rozszerzenia dla Gita. Dlatego jestem za używaniem Gita jako głównego repozytorium, nawet gdy preferujesz Mercurial. W projektach prowadzonych za pomocą Mercurial często znajdziemy woluntariusza, który równolegle prowadzi repozytorium Gita, dzięki pomocy rozszerzenia hg-git projekty Gita automatycznie osiągają użytkowników Mercurial.

To rozszerzenie potrafi również zmienić skład Mercurial w skład Gita, za pomocą komendy push do gołego repozytorium Gita. Jeszcze łatwiej dokonamy tego skryptem hg-fast-export.sh, który możemy tu znaleźć:

$ git clone git://repo.or.cz/fast-export.git

Aby skonwertować, wejdź do pustego katalogu:

$ git init
$ hg-fast-export.sh -r /hg/repo

po uprzednim dodaniu skryptu do twojego $ PATH.

Bazaar

Wspomnijmy również pokrótce o Bazaar, ponieważ jest to najbardziej popularny darmowy rozproszony system kontroli wersji po Git i Mercurial.

Bazar będąc stosunkowo młodym systemem, posiada zaletę perspektywy czasu, jego twórcy mogli uczyć się na błędach z przeszłości i uniknąć historycznych naleciałości. Poza tym programiści byli świadomi popularności i wagi interakcji z innymi systemami kontroli wersji.

Rozszerzenie Bzr-git pozwala użytkownikom Bazar dość łatwo pracować z repozytoriami Gita. Program tailor konwertuje składy Bazaar do składów Gita i może robić to na bieżąco, podczas gdy bzr-fast-export lepiej nadaje się do jednorazowej konwersji.

Dlaczego korzystam z Gita

Zdecydowałem się pierwotnie do wyboru Gita, ponieważ słyszałem, że jest w stanie zarządzać tak zawiłym i rozległym projektem jak kod źródłowy Linuksa. Jak na razie nie miałem powodów do zmiany. Git służył mi znakomicie i do tej pory mnie nie zawiódł. Ponieważ w pierwszej linii pracuję na Linuksie, problemy innych platform nie mają dla mnie znaczenia.

Preferuję również programy C i skrypty bash w opozycji do na przykład Pythona: posiadają mniej zależności, wolę też, gdy kod jest wykonywany szybko.

Myślałem już też nad tym, jak można by ulepszyć Gita, poszło to nawet tak daleko, że napisałem własną aplikacje podobną do niego, w celu jednak wyłącznie ćwiczeń akademickich. Nawet gdybym zakończył mój projekt, mimo to pozostałbym przy Git, bo ulepszenia byłyby zbyt minimalne by uzasadnić zastosowanie odosobnionego systemu.

Oczywiście może się okazać, że twoje potrzeby i oczekiwania są zupełnie inne i być może wygodniej jest tobie z zupełnie innym systemem. Jakby jednak nie spojrzeć, stosując Git nie popełnisz tu niczego złego.