Git tips: git daemon pod kontrolą dewelopera
Opublikował siefca
System kontroli wersji Git pozwala na dostęp do repozytorium z użyciem nie tylko protokołu SSH czy DAV, ale również, a może przede wszystkim, autorskiego protokołu Git. Komunikacja nie jest szyfrowana i dlatego jest on wykorzystywany do publicznego udostępniania repozytoriów w trybie tylko do odczytu. Działa to w ten sposób, że administrator maszyny, na której znajduje się repozytorium (może mu towarzyszyć kopia robocza, ale nie musi) podejmuje decyzję o uruchomieniu usługi git-daemon. Jej zadaniem jest zaglądać do repozytoriów i w razie nadejścia żądania pochodzącego z sieci uruchamiać odpowiednie podprogramy wchodzące w skład Gita. Dzięki temu można użyć polecenia git clone i pobrać kopię tak udostępnionego repozytorium.
Oto przykład wywołania usługi z internetowego superserwera inetd:
git stream tcp nowait git /usr/bin/git-daemon \ git-daemon --inetd --verbose --interpolated-path=/repo/%D /repo
(Dla czytelności złamałem linię.)
Taka konfiguracja sprawi, że katalog /repo będzie przeszukiwany pod kątem znalezienia w nim podkatalogów z repozytoriami Gita. Istotna jest tu również opcja --interpolated-path – zapewnia ona wygodę polegającą na tym, że zdalny klient nie musi podawać pełnej nazwy ścieżkowej określającej lokalizację repozytorium w naszym systemie plików. Dziwi mnie trochę, że w Sieci nie znalazłem przykładów wykorzystania tej opcji i musiałem posłużyć się metodą prób i błędów. Stosując ten zapis sprawiamy, że zdalny użytkownik nie będzie wiedział jak wygląda struktura systemu plików naszej maszyny, a poza tym mniej zmęczy palce – zamiast pisać np. git clone http://mojadomena.pp/var/srv/repozytoria/wzium.git będzie mógł wyklikać git clone git://mojadomena.pp/wzium.git.
Udostępnianie
Gdy demon już działa, to jeszcze nie udostępni znalezionego repozytorium, ale sprawdzi najpierw, czy w jego plikach kontrolnych znajduje się zbiór o nazwie git-daemon-export-ok. Te pliki kontrolne w przypadku repozytorium lokalnego, z kopią roboczą, znajdują się w podkatalogu .git, natomiast w przypadku serwera z samoistnymi repozytoriami w ich katalogach.
Istnienie takiego zbioru świadczy o zgodzie właściciela repozytorium na to, aby było ono publicznie widoczne. Wszystko pięknie, jednak mamy tu ukryte założenie, że właścicielem jest ten, kto ma prawo tworzenia plików, tzn. że na przykład programista może zakładać i usuwać w katalogu repozytorium na serwerze plik o wspomnianej nazwie. Rodzi to pewne kłopoty tam, gdzie mamy zdalne repozytorium, względem którego synchronizowane są zasoby pochodzące od wielu programistów, a my nie chcemy im wszystkim dawać dostępu do powłoki systemowej, a tym bardziej prawa do tworzenia czy usuwania jakichś kontrolnych zbiorów. Współdzielenie jednego systemowego konta z możliwością wydawania dowolnych poleceń też wydaje się mało atrakcyjną dla administratora opcją.
Jedno konto, wiele repozytoriów
Istnieją na szczęście proste narzędzia, dzięki którym można kontrolować dostęp do repozytoriów, ale bez wykorzystania systemowych mechanizmów dostępu. Na przykład na jednym z moich systemów używam pakietu gitosis, który pomaga w tym, aby wielu użytkowników mogło korzystać z jednego systemowego konta służącego wyłącznie do zdalnego przechowywania repozytoriów. Takie zdalne miejsce na kody przydaje się, gdy mamy grupę deweloperów, którzy muszą wymieniać się kodem. Poza tym z takiego miejsca można potem łatwo wdrażać na serwery aplikacyjne oznaczone jakimś tagiem wydania oprogramowania.
Użytkownicy w gitosis współdzielą wprawdzie jedno systemowe konto, ale są rozpoznawani nie po nazwach użytkownika, ale po kluczach publicznych używanych przez SSH, które administrator usługi dodał do odpowiedniego katalogu – nawiasem mówiąc, również korzystając z Gita. Oczywiście nie mogą wykonywać poleceń innych niż te ze zbioru git-, co w praktyce oznacza, że do takiego systemowego konta możliwy jest jedynie dostęp z użyciem Gita.
Ma to jednak pewien minus: deweloperzy nie mogą tworzyć plików w zdalnym katalogu repozytorium. Mam tu na myśli zbiory kontrolne w samoistnym (lub jak kto woli w “gołym”) repozytorium po drugiej stronie, a nie pliki objęte systemem kontroli wersji. Trudno więc o to, żeby deweloper samodzielnie stworzył git-daemon-export-ok. Z pomocą może tu przyjść uczynny admin, ale to jest chyba oksymoronem, więc pominiemy tę anomalię. Aby zaradzić problemowi należy stworzyć jakiś prosty system, który pozwoli osobie z prawem zapisu do repozytorium tworzyć lub kasować ten pojedynczy plik kontrolny po stronie serwera.
Wyświetlanie plików po stronie serwera
Pomyślałem, że w sumie byłoby całkiem ok, w przypadku mojego środowiska, gdyby to plik w katalogu objętym systemem kontroli wersji zarządzał udostępnianiem. Jednak na serwerze trudno szukać zbiorów zauważonych przed wysłaniem w kopii roboczej u dewelopera. Po prostu repozytorium posługuje się bazą obiektów, a nie przechowuje struktury takiej, jaką ma katalog z objętym kontrolą wersji projektem. Należy więc w jakiś sposób zbadać zwartość repozytorium po stronie serwera i móc chociażby wyświetlić zawarte w nim pliki. Na szczęście da się to zrobić poleceniem git-ls-tree (i pewnie jeszcze jakimś innym, o którym teraz nie wiem). Mamy więc możliwość dowiedzieć się na serwerze, jakie pliki zostały objęte kontrolą wersji, zaglądając do reprezentujących je obiektów. Przydałoby się jeszcze jakoś tworzyć wspomniany zbiór kontrolny tam gdzie trzeba, w zależności od umownego sygnału, który będzie polegał na wykryciu istnienia jakiegoś pliku.
Hooks
Tu z pomocą przychodzi tzw. hak (ang. hook). Haki pozwalają na wykonywanie pewnych akcji, gdy w repozytorium wystąpi jakieś zdarzenie (np. odebranie wysyłanych przez kogoś danych). Są to po prostu skrypty, które znajdują się w podkatalogu repozytorium o nazwie hooks. Jeden z nich nazywa się post-update i jest wykonywany za każdym razem po tym, gdy coś w repozytorium się zmieni (wystąpi aktualizacja).
Założenie jest więc takie: jeśli wśród plików objętych systemem kontroli wersji wchodzących w skład repozytorium pojawi się zbiór o nazwie np. .public-repo to należy utworzyć plik git-daemon-export-ok w katalogu zawierającym repozytorium po stronie odbierającego. W ten sposób umożliwimy programistom podejmowanie samodzielnych decyzji odnośnie tego, czy repozytorium ma być widoczne, czy też nie.
Oto zawartość pliku post-update:
#!/bin/sh # # To enable this hook, make this file executable by "chmod +x post-update". if git-ls-tree --name-only HEAD | grep -q "^.public-repo$"; then touch git-daemon-export-ok else rm -f git-daemon-export-ok 2>/dev/null fi exec git-update-server-info
Plik ten należy uczynić wykonywalnym i umieścić w podkatalogu hooks znajdującym się w katalogu pojedynczego repozytorium po stronie serwera. Jeśli chcesz, żeby wszystkie nowo tworzone repozytoria miały taki uchwyt w postaci skryptu, to możesz umieścić go w tzw. szablonach, które u mnie znajdują się w /usr/share/git-core/templates.



