Git i Bazaar

Współpraca z Subversion

Współpracę z Subversion, z powodu popularności tego projektu, uważam za najważniejszą funkcję wszystkich innych systemów kontroli kodu. Rozproszone systemy kontroli kodu mają wiele zalet; polecam wykład Linusa Torvaldsa na ten temat. Nawet jeżeli uważasz, że jest lekko skrzywiony w stronę Gita, i tak warto posłuchać jego argumentów dotyczących rozproszej kontroli kodu.

Biorąc pod uwagę popularność Subversion, typowy scenariusz użycia polegałby na użyciu rozproszonego systemu kontroli wersji, użyciu go do wyciągnięcia kodu z Subversion, pracy z wieloma prywatnymi gałęziami, a na koniec przesłaniu zmian z powrotem na serwer Subversion.

Istnieje wiele rozproszonych systemów kontroli wersji, chciałbym przetestować wszystkie, ale mając ograniczoną ilość czasu, przetestowałem tylko Bazaar i Git.

Ten tutorial jest inspirowany znakomitym Git-SVN Crash Course.

Różnice pomiędzy Git i Bazaar

Gałąź i gałęźnik

W Bazaar, drzewo katalogów jest gałęzią. W Gicie, jest to raczej gałęźnik, czyli zasobnik na gałęzie. Ta różnica prowadzi do wielu różnic w użyciu tych programów. Na przykład, jeżeli chcesz stworzyć nową gałąź Bazaar, musisz stworzyć nowe drzewo katalogów na dysku. Jeżeli używasz Gita, możesz zrobić to samo w istniejącym katalogu.

Bazaar jest prosty: ponieważ można mieć tylko jedną gałąź kodu w jednym drzewie katalogów, wystarczy sama nazwa katalogu żeby pchać, ciągnąć i łączyć kod. W przypadku Gita, jest to bardziej skomplikowane, ponieważ musisz albo określać gałąź o którą ci chodzi, albo gałąź ta jest wybierana domyślnie, na przykład „bieżąca gałąź”.  

Przesyłanie kodu przez sieć

Widzę tutaj dwa spore punkty na korzyść Bazaar. Pierwszy jest taki, że Git musi być zainstalowany na zdalnym serwerze. Jeżeli akurat używasz Dreamhosta, musisz zrobić własną instalację Gita; skompilować go, zainstalować w $HOME/bin, ustawić $PATH itd. Są też inne sposoby, ale nie zmienia to faktu że jeżeli spróbujesz po prostu pchnąć kod na ssh://example.com/katalog, dostaniesz błąd. Jeżeli nagle pojawi się potrzeba wrzuceniu repozytorium Git na inny serwer, musisz powtarzać całą operację. Bazaar potrafi czytać i kod ze zdalnych serwerów przez ssh (sftp), nie wymagając przy tym zdalnej instalacji Bazaar. Bardzo wygodne.

Drugi punkt dla Bazaar to tworzenie zdalnego repozytorium. Używając Bazar, możesz po prostu podać nowy URL, dodać opcję --create-prefix i gotowe. Git wymaga zalogowania się na zdalny serwer, gdzie trzeba ręcznie stworzyć repozytorium.  

Metadane Subversion

Podczas klonowania repozytoriów Git, metadane Subversion są pomijane; nie można sklonować repozytorium Git, a potem pchnąć kod do Subversion z nowego repozytorium. Innymi słowy, można przesyłać dane z powrotem do Subversion tylko z miejsca w którym się te dane wyciągało (przy pomocy git-svn).

W przeciwieństwie do Gita, Bazaar potrafi pchać zmiany do Subversion z dowolnej gałęzi. Można wyciąganąć kod z Subversion, potem go rozgałęzić, w nowej gałęzi wprowadzić własne zmiany i wrzucić je do Subversion.  

Wymagane wersje

Ten tutorial został napisany przy użyciu Git 1.5.2.1 i Bazaar 0.17.0.

Uruchomienie obydwu na jednym komputerze nie jest zbyt proste w momencie pisania tego tutoriala. Współpraca z Subversion wymaga nowej jej wersji. Nie mogłem jej łatwo zainstalować, bo nie było jej w Gentoo Portage. Ubuntu Feisty Fawn ma załataną wersję Subversion, ale ma z kolei Gita 1.4, który sporo różni się od 1.5. Innymi „słowy”:

  Gentoo 2007.0 Ubuntu 7.04
Subversion 1.3 (za stary) 1.3 załatany
Git 1.5 1.4

Pod Gentoo, można zainstalować Subversion 1.4, dodając flagę ~x86 do /etc/portage/package.keywords. Ja zrobiłem inaczej: skompilowałem Gita 1.5 ze źródeł pod Ubuntu 7.04. Można też tak jak podpowiada i0:

pod Feistym można zainstalować Git 1.5 z backportowego repozytorium deb-src Gutsy’ego, służy do tego Prevu — buduje pakiety (także dla starszych wersji Ubuntu), które można zainstalować z lokalnego repozytorium.

Kod łączący Bazaar i Subversion w Ubuntu jest instalowany razem z samym Bazaar; w przypadku innych dystrybucji może być potrzebne zainstalowanie osobnego pakietu.

Żeby przerobić całość tego tutoriala, musisz mieć dostęp do zapisu w jakimś repozytorium Subversion. Jeżeli nie masz możliwości zapisu w żadnym repozytorium Subversion, nie będziesz w stanie przesłać z powrotem swojego kodu, co z jednej strony jest całym sensem tego tutoriala, ale z drugiej strony ten tutorial będzie równie pomocy osobom które chcą wziąć kod z jakiegoś projektu, powiedzmy na Sourceforge, i się nim pobawić. To było najdłuższe zdanie z tego tutoriala. Jeżeli je przeczytałeś, najgorsze masz już za sobą.

Właściwy tutorial

Pobieranie kodu z Subversion

Powiedzmy że masz standardowy, zalecany układ repozytorium Subversion z katalogami trunk, branches i tags.

.
|-- branches
|-- tags
`-- trunk

Możesz zaimportować wszystkie gałęzie (branches) i tagi do Gita, ale do Bazaar możesz zaimportować tylko trunk, stąd url/trunk.

git-svn clone -T trunk -b branches -t tags url
bzr branch url/trunk

Wprowadzanie lokalnych zmian

Możesz wyedytować jakiś plik. Kiedy skończysz, musisz zatwierdzić (commit) swoje zmiany. Tutaj dochodzimy do pierwszej różnicy pomiędzy scentralizowanym i rozproszonym systemem kontroli kodu: tutaj nie zatwierdza się przesyłając dane do serwera, wszystko dzieje się lokalnie.

git commit -a bzr commit

Przesyłanie zmian z powrotem do Subversion

git-svn dcommit bzr push url/trunk

Może się zdarzyć, że ktoś w międzyczasie prześle zmiany do głównego repozytorium Subversion. Nie możesz po prostu zatwierdzić (commit) swoich zmian, bo… już je zatwierdziłeś! Do swojego lokalnego repozytorium. A ponieważ ktoś zatwierdził swoje zmiany w centralnym repozytorium Subversion, gałęzie te się rozszczepiły. Musisz je połączyć.

Łączenie zmian w Gicie czy Bazaar wygląda mocno inaczej niż to z czym mamy do czynienia w Subversion. Nie trzeba pamiętać żadnych numerów wersji. Nie trzeba się w ogóle martwić całym tym badziewiem, ani spędzać nad tym połowy dnia. Można po prostu połączyć zmiany.

Jest też różnica pomiędzy Git i Bazaar w łączeniu. W Bazaar, łączy się zmiany z Subversion z gałęzią, w jednym kroku. W Gicie potrzeba dwóch kroków. Najpierw uaktualnia się zdalną gałąź, nazwaną trunk, a następnie połączyć zmiany z tego trunk z bieżącą gałęzią. Druga różnica jest taka, że w Bazaar, po złączeniu, trzeba jeszcze zatwierdzić zmiany. W Gicie, o ile nie było konfliktów, nie ma takiej potrzeby.

git-svn fetch bzr merge url/trunk
git merge remotes/trunk  

W tym momencie, ponieważ łączysz zmiany, możesz napotkać konflikty w kodzie. Rozwiązanie ich należy do ciebie. Git ma coś co się nazywa git-mergetool. Narzędzie to używa domyślnie Emacsa. Jeżeli chcesz, możesz poprosić je o użycie Vima.

git-mergetool -t vimdiff bzr resolve file
git commit -a bzr commit

Teraz masz już złączone zmiany ze zdalnej gałęzi, konflikty rozwiązane i zatwierdzone. Uprzednio rozwidlone gałęzie są z powrotem połączone. Można pchnąć zmiany na serwer.

git-svn dcommit bzr push url/trunk

Tworzenie nowej gałęzi

Dla Gita oznacza to coś trochę innego niż dla Bazaar. Używając Gita, tworzy się nową gałąź w tym samym drzewie katalogów; w Bazaar tworzy się nowe drzewo.

git checkout -b branch
bzr branch file:///path new-path

Łączenie zmian pomiędzy gałęziami

Zarówno w Git jak i w Bazaar, łączenie odbywa się poprzez „ciągnięcie” (w przeciwieństwie do pchania) zmian.

git merge branch
bzr merge url
bzr commit

Pchanie zmian na USB pendrive

Jeżeli chcesz przenosić kod pomiędzy kilkoma komputerami, możesz użyć „gwizdka” USB. Konwencja nazw *.git służy do oznaczania tzw. „gołych” repozytoriów.

git clone --bare path /media/Pendrive/my-project.git
bzr push file:///new-path --create-prefix

Tutaj, path oznacza ścieżkę do drzewa katalogów ze źródłami. Jest jeszcze jedna różnica pomiędzy Git i Bazaar; Git nie posiada opcji --create-prefix. Jeżeli chcesz utworzyć nowe drzewo katalogów na gwizdku, musisz użyć funkcji clone, która oznacza raczej ciągnięcie niż pchanie.

Możesz później sklonować repozytorium z gwizdka na lokalny dysk na innym komputerze.

git clone /media/Pendrive/my-project.git my-project
bzr branch file:///media/Pendrive/my-project

Przesyłanie zmian przez sieć

Gwizdek USB mi nie wystarcza; często chcę przesyłać zmiany przez sieć. Stosunkowo łatwe rozwiązanie polega na użyciu serwera na którym ma się konto z dostępem przez ssh. Jeżeli masz zainstalowany sshfs, możesz podmontować zdalny katalog i używać go tak jakby był lokalny.

sshfs -C user@example.com:/home/user ~/foo \
-o idmap=user -o workaround=rename \
-o uid=$UID -o gid=$(id -g)

Nie pytajcie mnie o te dziwne opcje. One są po to żeby naprawić jakiś problem z czymś, rozpracowałem to już jakiś czas temu i wszystkie informacje na ten temat zostały już wypłukane przez strumień artykułów z reddit.com na temat Haskella.

Jeżeli używasz Bazaar, przesyłanie przez sieć jest łatwiejsze. Możesz po prostu:

bzr push sftp://user@example.com/home/user/my-project \
--create-prefix

Opcja --create-prefix jest potrzebna tylko za pierwszym razem. Później można:

bzr push sftp://user@example.com/home/user/my-project

Posłowie

Przepraszam za brzydkie słowo powyżej.

Ten tutorial jest tylko przejściem przez kilka podstawowych funkcji Git i Bazaar; w żaden sposób nie wyczerpuje tematu. Wszelkie sugestie są mile widziane. Możesz do mnie napisać na:

python -c "print 'bWFjaWVqLmJsaXppbnNraUBnbWFpbC5jb20='.decode('base64')" 

Copyright© 2007 Maciej Bliziński.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

Last modified on Mon Dec 17 23:24:07 +0000 2007.