Git jest the best – to wie chyba każdy kto czyta tego bloga. Może niekoniecznie się z tym zgadza, ale przynajmniej wie:). Wydaje mi się, że to jedyny kawałek softu, na który nigdy nie narzekałem…
Aż do niedawna. Przyszło mi pracować przy wieloletnim projekcie, którego repozytorium liczone było w gigabajtach. Za pomocą Git-TFS ściągnąłem sobie historię, a tam, jak się można domyślić, cały TfuFSowy syf. Czyli na przykład wszystkie branche będące kopiami, kropka w kropkę, plików pomiędzy jedną gałęzią a drugą (co za geniusz to w ogóle wymyślił?). Do tego masa dokumentów i starego kodu, z którym nie mam nic do czynienia. Okazało się, że Git niestety dostał zadyszki. Mimo 16GB RAMu, mimo SSD… (ciekawostka: niedawno Facebook też w tą pułapkę wpadł, tyle że oni pewnie z innych powodów). Rekomendowanym sposobem radzenia sobie z tym problemem jest odpowiednia organizacja kodu – dzielenie go na osobne repozytoria linkowane między sobą jako git submodules.
Z tym że jest jedno wielkie ALE – jeśli cały kod siedzi w TfuFS a ja sobie lokalnie używam Git to nic z tym nie zrobię. No ale jak to “nic z tym nie zrobię” skoro “git status” czy “git commit” trwają po kilkanaście sekund? Nie wspominając nawet o wielokrotnym rebase koniecznym przy komendzie rcheckin? I tak wolę takiego Gita niż TfuFSa, ale…
Na szczęście rozwiązanie się znalazło, i to prostsze niż można by się spodziewać. Taka a nie inna wydajność Gita spowodowana jest tym, że przy każdej operacji musi on przemielić te moje wszystkie gigabajty. Nic dziwnego, że się dusi (chociaż byłoby miło, gdyby tak nie było). Wystarczy jednak mieć w “working copy” tylko to co mi jest potrzebne, wszystkie pozostałe śmieci zostawiając w katalogu .git, i znowu jest cudownie! Mechanizm taki znany był już w SVN pod hasłem “partial checkout”. W Gicie nazywa się to “sparse checkout” i oto jak z jego dobrodziejstw można skorzystać:
Najpierw włączamy taki tryb pracy w konfiguracji repozytorium:
git config core.sparsecheckout true
Następnie tworzymy plik .git/info/sparse-checkout i wrzucamy do niego katalogi, które chcemy mieć w working copy. Wstawiamy jeden wpis per linia, np:
Dev/Main Config/Scripts
Możemy tutaj stosować patterns na nazwach plików i katalogów, jak w każdym innym miejscu Gita. Możemy też stosować negacje – wystarczy wykrzyknik z przodu linii.
Na koniec robimy użytek z powyższych czynności wywołując komendę:
git read-tree -m -u HEAD
I już. Cieszymy się ponownie niepokonaną szybkością działania.
Jeśli chcemy zmienić konfigurację sparse checkout to po prostu modyfikujemy plik ze ścieżkami i wykonujemy ponownie read-tree.
I tyle. Git znowu nie ma wad.
P.S. Gutek bardzo się ucieszył jak mu o tym powiedziałem, ale z innych powodów. Chciał zrobić checkout ZMIENIAJĄC strukturę katalogów – czyli na przykład żeby źródła trzymane w /root/dev/main/proj/src mieć bezpośrednio w /root/src. Takiego czegoś niestety nie ma.
UPDATE
Wygląda na to że to nie jest takie cudowne rozwiązanie – git tfs rcheckin wydaje się zdezorientowane zamieszaniem. checkintool nadal działa, ale moja ulubiona komenda z git-tfs nie chce. Zrobię kolejny update jeśli znajdę rozwiązanie, póki co założyłem issue na githubie.
UPDATE 2
Microsoftowy projekt Git-TF potrafi obsłużyć sparse checkouts, więc na razie przesiadam się na niego.
Odzyskiwanie wydajności Git w dużym repozytorium: sparse checkout | Maciej Aniserowicz o programowaniu…
Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl…
Witam,
Można jeszcze spróbować polecenia git gc, albo najlepiej git gc –agressive. To także usuwa niepotrzebne śmieci i optymalizuje lokalne repo. Warto od czasu do czasu trochę “odświeżyć” w ten sposób repo.
Więcej info pod: http://www.kernel.org/pub/software/scm/git/docs/git-gc.html
Pozdrawiam, pandominox.
pandominox,
To prawda, ale GC porzadkuje samo repozytorium. Przy tak wielkim working copy niewiele daje – sprawdzałem:).
Cóż…tak myślałam, że raczej tym gc nie zaskoczę “starego” gitowego wyjadacza…zawsze warto jednak spróbować ;)
Pozdrawiam, pandominox.
pandominox,
Nie na jasne, każda sugestia jest spoko:). Dodatkowo Git sam czasami odpala optymalizację katalogu .git gdy uzna że zachodzi taka potrzeba (zaobserwowałem to np przy kontakcie z remote repo).
Na początku – dzięki – przekonałeś mnie jakiś czas temu do GIT-a i jestem równie entuzjastyczny :)
A teraz pytanie dotyczące posta:
Czy dobrze rozumiem że dzięki temu poleceniu można mieć w jednym repo np. 3 projekty (powiązane) i pracować tylko na jednym projekcie ?
Czyli:
Repo:
Projekt/główny program
Projekt/biblioteka API
Projekt/Biblioteka wewnętrna
I mogę ściągnąć tylko jeden katalog ? (np: projekt/główny program ?)
Pozdrawiam i dziękuję za bloga,
MWW
MWW,
Spoko, cieszę się:).
Repozytorium zawsze ściąga się/klonuje całe do katalogu .git. Ta komenda pozwala po prostu na zredukowanie liczby plików “wyciągniętych” do working copy co ma znaczący wpływ na wydajność przy dużym projekcie. No i pozwala oczyścić widok dysku. Więc tak – to służy dokładnie temu co napisałeś… przy założeniu że główny program nie wymaga do działania (np nie ma referencji do) API czy drugiej biblioteki. Ich po prostu nie będzie na dysku.
Maciek, a nie probówałeś mapować tylko branch, na którym pracujesz bez innych branchy? Przykładowo tylko Projekt\main, a nie cały Projekt. Widzę, że istnieją foldery w głównym katalogu projektu (np. Config/Scripts), ale to też nie widzę problemu, żeby mapować je ręcznie.
Michał,
Ściągając Gitem kod z TfuFSa nie ma obsługi gałęzi – ściąga się wszystko. Dotyczy to zarówno Git-TFS jak i Git-TF. A wpisy z pliku konfiguracyjnego są fake:).
Michał,
Mój błąd, okazało się że MOŻNA za pomocą git-tfs ściągnąć tylko jeden wybrany katalog.
Wygląda na to że już nie będziesz musiał narzekać na TfuFSa ;)
Sorki, że wrzucam to jako comment po niezbyt świeży post, ale jak się na to natknąłem, to od razu pomyślałem o Tobie: http://channel9.msdn.com/posts/GitForVisualStudioTFS
Pozdrawiam
zabanet,
Thx za linka, i za myśl o mnie;). Widziałem, ciekawe jak sie sprawdzi w praktyce. BTW co to za durna moda żeby wszystko robić jako video…
[…] natknąłem się na ograniczenie w Git-TFS (chodzi o obsługę opisywanego sparse checkout). Skłoniło mnie to do przetestowania Git-TF… a poniżej moje […]