Git - system kontroli wersji, który powinien znać każdy
24 komentarze | Kategorie: Git, Narzędzia, Techblog | trackbackTagi: git scm svn
Witam po kolejnej długiej przerwie. Ponieważ ostatnio nie za bardzo mam czas na pisanie porządnych wpisów (czyli takich gdzie muszę dobrze przemyśleć temat, poszperać w internecie, dodać swoje przemyślenia - a zajmuje dobre kilka godzin) to tym razem trochę w innym stylu. Bez kodu, bez przykładów. Ba, temat nawet nie będzie dotyczył Rubiego!
A jak nie chodzi o Ruby to chodzi o Git! Chciałbym podzielić się z Wami moimi spostrzeżeniami na temat tego narzędzia.
Mniej więcej rok temu zetknąłem się z gitem. Pamiętam, że obejrzałem film video Linus Torvalds on git. Chociaż nie do końca trafił do mnie (nie potrafiłem np. pojąć idei rozproszoności), to sposób w jaki Linus opowiadał o nim sprawił, że miałem ochotę zgłębić temat. Tak też zrobiłem. Opinie internautów, jak i moje pierwsze doświadczenie z gitem, potwierdzały, że jest to świetne narzędzie. Niestety okazało się także, że jest to stosunkowo trudne narzędzie.
Początkowe trudności wynikały głównie z dwóch powodów. Po pierwsze git pokazał, że znane mi do tej pory narzędzia do kontroli kodu źródłowego (czyli głównie svn, a w przeszłości także cvs), używam w dosyć prymitywny sposób i ogranicza się to mniej więcej do komend "update, commit, status". Po drugie, toporność pewnych czynności (powiedzmy, że "bardziej zaawansowanych") jakie należy wykonać we wspomnianym svn sprawiała, że albo ich świadomie nie używałem, albo po prostu nie wiedziałem, że istnieją. Z moich obserwacji wynika, że większość programistów ma podobne doświadczenie z svn i podobnymi systemami kontroli wersji. Poniższej zamieszczam dosyć luźno opisane aspektu gita, które najbardziej mnie zaskoczyły, utkwiły w pamięci i zmieniły sposób w jaki teraz tego typu narzędzi używam.
Tworzenie nowego repozytorium
Git od samego początku zachwyca. Założenie nowego repozytorium to kwestia jednego polecenia git init, wydanego z katalogu z projektem. Choć mogłoby się wydawać, że nie jest to zbyt istotne (w końcu jak często zakładamy nowe repozytorium?) to dzięki temu otwierają się przed nami nowe możliwości. Nie raz zdarzało mi się, że musiałem "pogrzebać" w jakimś katalogu/kodzie, ale nie chciałem stracić starej zawartości. Bawienie się w kopie jest uciążliwe, teraz używam do tego gita. Co ciekawe git tworzy tylko jeden katalog o nazwie .git, zatem ewentualne usunięcie repozytorium to kwestia skasowania tego katalogu.
Rozproszoność
Jedną z najczęściej powtarzanych i podkreślanych cech gita jest rozproszoność. W uproszczeniu polega to na tym, że każdy kto skopiuje (sklonuje) repozytorium ma wszystkie zawarte w nim informacje. W szczególności jest to cała historia. Wszystkie te informacje zawarte są we wspomnianym katalogu .git. Od momentu wykonania operacji clone stajemy się właścicielami własnego, prywatnego, lokalnego repozytorium. Jedynie operacje synchronizacji repozytoriów (w końcu musimy wymienić z innymi dane) wymagają dostępu do sieci. Każda inna jest lokalna i nie dość, że mogą nam odciąć kabel a i tak będzie wszystko działać, to jeszcze brak opóźnień operacji sieciowych odczujemy momentalnie (przypomnij sobie te kilkunastosekundowe lagi po wydaniu polecania svn log).
Rozmiar repozytorium
Pomimo tego, że klonując repozytorium gita pobieramy całą jego historię, rozmiar katalogu z projektem nie jest o wiele większy niż gdybyśmy użyli pojedynczego "checkouta" svn, a często jest nawet większy (pamiętajmy, że svn tworzy ogromną ilość podkatalogów o nazwie .svn. Dla przykładu repozytorium ze źródłami Django pod kontrolą gita zajmował 43MB, zaś pod kontrolą svna 61MB (źródło). Z kolei projekt, przy którym obecnie pracuję, przy ponad 3000 rewizjach zajmuje ~22MB z czego 7MB to cała historia, a pozostałe 15MB to rozmiar pojedynczego checkouta.
Gałęzie
Jest to jedna z tych cech gita, o których mógłbym pi(s)ać peany na jej cześć. Przed gitem nigdy nie używałem gałęzi. Projekty były "jednotokowe" (czyli "trunk" i cała naprzód). Brzmi znajomo? Podejrzewam, że tak...
Git maksymalnie upraszcza prace na gałęziach. Tworzenie gałęzi trwa ułamek sekundy (bo tyle trwa utworzenie i zapis 41 bajtów do pliku) a przełączanie się między nimi jest tylko ciut wolniejsze (w praktyce zależy od ilości różnic między przełączanymi gałęziami). Co ciekawe w gicie pracujemy na różnych gałęziach używając tego samego katalogu roboczego - zupełnie inaczej niż w svn, gdzie każda gałąź (tag) jest osobną kopią. Nie musimy się więc ograniczać co do ich ilości (osobiście tworzę osobny branch dla każdej zmiany). Chociaż jeśli komuś ten sposób nie podoba się to nic nie stoi na przeszkodzie by utworzyć dodatkowe klony w oddzielnych katalogach (tylko po co?).
Lokalność
Wspomniałem już o tym, że git jest rozproszony. Pochodną tej cechy jest fakt, że większość operacji na repozytorium jest lokalna. Nie doceniłem tego faktu, aż do wspomnianego momentu, gdy praca z repozytorium była czymś więcej niż "update, commit, status". I tak na prawdę nie chodzi mi o to, że możemy pracować odpięci od sieci (przecież niedużo nam trzeba, żeby mieć internet w lodówce), ale o prędkość i niezależność poleceń. Przykład? A choćby najprostsze git log trwa ułamek sekundy. Chcąc wyszukać commity, które zawierają w zmianach słowo "foo", wpisuję git log -S"foo" i wręcz natychmiast dostaję wyniki (dzięki temu szybko znajdę informację kto i kiedy dodał/usunął daną klasę/metodę itp.). Gdy czeka nas jakieś większe łączenie gałęzi, możemy pociągnąć wszystkie zmiany ze zdalnego repozytorium (git fetch) i od tego momentu działać lokalnie. Wspomniana lekkość i łatwość tworzenia branchy, daje nam możliwość bezstresowego próbowania różnych kombinacji. Jeśli coś nam nie wyjdzie, zawsze możemy szybko wrócić do stanu początkowego.
Perełki
Na koniec zostawiłem kilka ciekawych przykładów. Są to polecenia/narzędzia, która bardzo pozytywnie mnie zaskoczyły. Jednym z najczęściej używanych przeze mnie narzędzi jest gitk. Jest to graficzne narzędzie, które dosyć ładnie zwizualizuje nam powiązania commitów. Z uwagi na niezbyt nowoczesny wygląd GUI, może być z początku odbierany negatywnie, ale szybko się okazuje, że tak nie jest. W szczególności używam go do szybkiego przeglądu ostatnich zmian dokonanych przez innych (czyli robię fetch i przeglądam commity od master..origin/master).
Lista commitów, łatwy dostęp do diffów i inne informacje, które prezentuje nam gitk.
git cherry-pick pozwala na dołączania zmian z wybranych commitów z jednej gałęzi do drugiej. Przydatne jeśli posiadasz w projekcie gałąź rozwojową i produkcyjną i prowadzisz aktualne prace na tej pierwszej, ale czasem chciałbyś pociągnąć pewne zmiany do tej drugiej. Wtedy jednym poleceniem git cherry-pick SHA1 pociągasz zmiany i jeśli nie było konfliktu od razu jest tworzony commit.
Wyobraź sobie taką sytuację. Odpalasz aplikację, klikasz tu i tam, po czym okazuje się, że coś nie działa. Cóż, cudów nie ma, trzeba zlokalizować buga i go naprawić. I tu pojawiają się schody, bo pomimo iż dokładnie wiesz, która linijka powoduje błąd, to nie jesteś w stanie go poprawić bo błąd de facto siedzi w innej części systemu (nie trudno sobie wyobrazić takiej sytuacji, skoro aplikacja może być zależna od wielu zewnętrznych czynników takich jak użyte biblioteki, konfiguracja, system operacyjny, baza danych itp.). Jeśli dodatkowo towarzyszą Ci myśli "przecież to kiedyś działało!" to prawie na pewno potrzebujesz pomocy w postaci git bisect (mój ulubieniec). Idea jest prosta: znajdź pierwszy commit, który spowodował, że coś przestało działać. Jeśli wiesz, że kod sprzed tygodnia działał to informujesz o tym gita, następnie wskazujesz commit niedziałający (np. aktualny master) i rozpoczynasz binarne przeszukiwanie. Git pobiera jakąś wersję projektu, a Ty tylko odpowiadasz czy ten błąd występuje czy też nie. W ten sposób bardzo szybko (przypominam, że wyszukiwanie jest binarne) zostanie znaleziony commit, po którym to nasze "coś" przestało działać. Przyglądając się zmianom, które wniósł, możemy dosyć szybko wywnioskować, co jest przyczyną problemu (przykładowo, ktoś dokonał aktualizacji jakiejś biblioteki).
Podsumowanie
Uważam, że git to wspaniałe narzędzie. Nie jest to lek na całe zło zarządzania projektem od strony kodu źródłowego, ale ułatwia ogromną ilość spraw. Jest na pewno sporo trudniejszy do opanowania niż wspominany svn, ale każda chwila spędzona przy nauce tego narzędzia, zwraca nam się bardzo szybko. Moja osobista rada jest taka: jeśli w swoim zespole chcielibyście użyć tego narzędzia, to dobrze jest by przynajmniej jedna osoba miała dosyć dobrze opanowanego gita i w razie problemów (a na początku będą) będzie interweniować. W przeciwnym wypadku można się zniechęcić i nie dać szansy doznać olśnienia, którego niejeden doznał. Życzę miłego gitowania!
"Na koniec zostawiłem kilka ciekawych przykładów. Są to polecenia/narzędzia, która bardzo pozytywnie mnie zaskoczyły. Jednym z najczęściej używanych przeze mnie narzędzi jest gitk."
Jeśli ktoś woli QT to polecam qgit4 .
Warto też wspomnieć co jest napisane w Manualu o GIT - the stupid content tracker.
Używając dowolnego narzędzia do kontroli wersji warto jest poświęcić czas na poczytanie o nim.
Fajnie, że dzięki git-owi odkryłeś istnienie branchy czy przeglądarek commitów -- teraz pewnie nawet gdyby życie zmusiło Cię do używania SVN, to wykorzystałbyś więcej jego możliwości...
Rzuć okiem na tig – jakoś bardziej mi przypadł do gustu niż gitk. http://jonas.nitro.dk/tig/
Czy powinien znać każdy? Nie byłbym tego taki pewien. Głównie programiści pracujący pod Linuksem. Git ma spore możliwości i jest naprawdę szybki, ale i tak sporo mu do osiągnięcia popularności scentralizowanego Subversion, czy też rozproszonego oraz bardzo elastycznego Mercuriala.
To znaczy czego mu brakuje w porównaniu z Mercurialem? A raczej: co da mi Mercurial żebym rozważał przesiadkę na niego?
Zależności pod Windows w postaci Cygwina mnie nie przerażają, bo i tak go potrzebowałem, a dostępność serwisów do hostowania repozytoriów mnie nie interesuje, bo i tak mam wykupiony własny serwer.
@dozzie: A gdzie napisałem, że czegoś mu brakuje? I gdzie stwierdziłem, że masz się na niego przesiadać? ;] Pytam tak zadziornie z tego względu, iż pisałem o popularności oraz o tym, iż Mercurial zyskuje ją dzięki wspomnianej elastyczności.
Mój poprzedni komentarz może wyglądać, jak argument, ale w rzeczywistości bazuje na pewnej słabości ludzkiego myślenia skłaniającej do wykorzystywania schematów i heurystyk podczas podejmowania decyzji. Co nie zmienia faktu, że to, co napisałem może mieć realny wpływ na kształt rynku za kilka lat.
Warto wspomnieć też o git-bisect.
Musiałem ostatnio się z nim zapoznać przy próbie wyśledzenia błędu w sterowniku do radeona. Trzeba przyznać, że sprawdziło się rewelacyjnie.
Radarek, jeszcze pamiętaj wspomnieć o git-bisect, bo chyba nikt nie przypominał ;>
Mercurial zdaje się mieć dużo lepszy PR (a w zasadzie to PR Gita jest do kitu) i ma dzięki temu o wiele większą szansę, by przebić się w zastosowaniach enterprise (o ile w ogóle ktokolwiek potrzebuje tam DVCS).
@Hoppke: dokładnie tak myślę, tzn. moja ogólna wiedza na temat zarządzania wersjami źródeł powiększyła się. Git ma to do siebie, że zmusza na dosyć wczesnym etapie do poznania pewnych pojęć, czego nie robi wspomniany svn.
@Shot: na tiga ostatnio natrafiłem i będę chciał bliżej poznać to narzędzie, tym bardziej, że jest "konsolowe".
@Zal: może nie chodzi stricte o znanie gita, ale o dosyć dobre pojęcie o zarządzaniu kodem z poziomu systemu kontroli wersji. Nie chciałbym pochopnie wydawać pewnych sądów, ale przeciętny programista poza wspomniane dwukrotnie "update, commit, status" nie wychodzi i przy wielu sytuacjach po prostu się gupi ("nie mogę Ci skomitować tego jeszcze bo mam też inne zmiany i ich nie skończyłem" to tylko przykładowy problem, który akurat z svn jest dużo cięższy do rozwiązania niż z gitem - ale możliwy).
@Jacek Politowski: a przyglądnij się dobrze czy aby przypadkiem w tekście nie pojawiła się wzmianka o git bisect?:)
A co do samego mercuriala to podejrzewam, że idzie on w parze z gitem i nie ma sensu spierać się, które jest "lepsiejsze".
To ja polecę "gietekowe" http://live.gnome.org/giggle
Powiedzmy mam dwi gałęzie i chciałbym zcalić jeden plik między gałęziami. Jest to możliwe i jak?
git jest fajny, też go polubiłem. Ale dostrzegam jego wady, wspomniane już problemy pod windowsem. Uczestniczyłem kiedyś w projekcie, w którym branchy było ... dużo. Prawie do każdego większego zadania była tworzona nowa gałąź, a potem w dniu deploya ktoś próbował to wszystko mergować i wysłać na produkcję. Według mnie to już był jakiś antipattern. Ale to wszystko właśnie dzięki łatwości tworzenia gałęzi.
Ach, żeby giggle było GTK-owe... Ale nie, to wymaga połowy GNOME.
@DrLex: "scalić". I nie znam innej metody niż wycinanie chunków za pomocą patchutils i aplikowanie przez git-apply.
@Seban: a jakie to problemy pod Windows zostały wspomniane? Bo ja osobiście żadnych nie doświadczam.
Każdemu, który pracuje z Gitem mogą przydać się te linki:
http://github.com
http://ktown.kde.org/~zrusin/git/git-cheat-sheet-medium.png
To jaka w takim razie jest najlepsza strategia jeżeli mamy np. typowe Vanilla i konkretne wdrożenia gdzie różnicą jest zawartość plików konfiguracyjnych i np. szablony.
Czy należy robić osobne projekty, czy gałęzie?
@DrLex: ja nie widzę potrzeby, by tworzyć osobne gałęzie dla innej konfiguracji. Osobne gałęzie sugerują, że w pewnym momencie doszło do rozłamu aplikacji na różne wersje. Jeśli aplikacja jest konfigurowalna na N sposobów to nie oznacza to, że jest jej N rozgałęzionych wersji. Pliki konfiguracyjne możesz też trzymać w projekcie (app1_conf.yml, app2_conf.yml itp.), a przy deployu wybierać konkretny.
Przyjrzałem się - było :-)
Najwyraźniej coś musiało mnie oderwać od czytania i po powrocie nie pamiętałem, że całości wpisu nie przeczytałem... :-(
Według mnie, w poście brakuje wspomnienia o githubie, który walnie przyczynił się do popularyzacji gita wśród railsowców.
Są też gitcasty ,co prawda jeszcze nie miałem czasu żadnego z nich obejrzeć, ale myślę, że początkującym w gicie (np. ja ;)) mogą bardzo pomóc.
Pro Git - darmowa książka
W poprzednim komentarzu namarudziłem, a powinienem od razu:
Dzięki za świetny artykuł :) Dzięki twojej pracy wzrasta motywacja do nauki trudnych i świetnych narzędzi.
Pod OS-X jest b. ładny klient - GitX. Niedawno też twórcy świetnego SmartSVN wypuścili wersję pre-release noweo SmartGit.
Z graficznych narzędzi polecam gitg - bardzo podobne do wspomnianego już giggle. Mimo tych wszystkich graficznych klientów, zwykły alias do
log --pretty=format:'%h: %an - %ar - %s' --graphzawsze mi wystarczał.W tym artykule najbardziej podoba mi się, że podkreśliłeś stromą krzywą uczenia się. Git jest cholernie trudny do opanowania. Nieintuicyjny i śmierdzi Linuksem.
To powiedziawszy, po ponad 2 latach Gita nie wyobrażam sobie korzystania z innego repo! W praktyce najbardziej przydaje się błyskawiczne działanie, w tym błyskawiczne tworzenie gałęzi i merge. Sama rozproszoność nie bardzo mi się na razie przydała. No i Github, to jest w ogóle nowa kultura współpracy i wizualizacji tej współpracy.
Z graficznych narzędzi polecam wsparcie dla Gita w RubyMine.