Git świetnie radzi sobie z tekstem i różnicami linia po linii. Plik Maya na dwa gigabajty tego nie ma — i to jedna z tych rzeczy, które łamią intuicję programisty wchodzącego do VFX.
Programista, który trafia do VFX, zwykle zadaje to samo pytanie: skoro Git tak dobrze sprawdza się w kodzie, dlaczego cała branża nie wersjonuje nim po prostu wszystkiego? Odpowiedź nie jest oczywista, dopóki nie zrozumiesz, na jakim założeniu Git w ogóle stoi — i dlaczego pliki, z którymi pracuje modelarka czy artysta FX, to założenie łamią niemal natychmiast.
Git został zbudowany wokół jednej idei: zmiana w pliku tekstowym da się zapisać jako różnica — które linie zniknęły, które się pojawiły. Kiedy dwie osoby edytują ten sam plik kodu w różnych miejscach, Git potrafi automatycznie połączyć obie zmiany w jeden, spójny wynik — to właśnie merge. Do tego każdy, kto sklonuje repozytorium, dostaje pełną historię wszystkich zmian od początku istnienia projektu, przechowywaną lokalnie — stąd określenie „system rozproszony".
specularRoughness = 0.4 - ambientColor = 0.2 + ambientColor = 0.35 refractionIndex = 1.5
To działa bez zarzutu, dopóki plik jest tekstem — kodem źródłowym narzędzia, plikiem konfiguracyjnym, configiem OpenColorIO z Rozdziału 12. Git widzi każdą linię z osobna, wie dokładnie, co się zmieniło, i potrafi to zmienione miejsce wskazać.
Plik sceny Maya, cache Alembica czy plik tekstury nie są zapisane jako linie, które można porównać. To formaty binarne — ciągi bajtów o wewnętrznej strukturze zrozumiałej tylko dla programu, który je stworzył. Dla Gita dwie wersje takiego pliku wyglądają tak:
hero_char_v1.mb → 2 847 391 kB — zmieniło się: nieznane (format binarny) hero_char_v2.mb → 2 851 022 kB — zmieniło się: nieznane (format binarny)
Git nie ma sposobu, żeby powiedzieć „zmieniła się tylko pozycja jednego palca lewej dłoni". Widzi dwa całkowicie różne bloby i przy każdym commicie zapisuje kolejną, pełną kopię całego pliku. To ma dwie poważne konsekwencje. Po pierwsze — brak mergowania: jeśli riger i modelarka oboje otworzą hero_char.mb, oboje wprowadzą zmiany i oboje spróbują je zapisać, Git nie potrafi połączyć ich pracy tak, jak łączy dwie linie kodu. Ktoś commituje jako drugi i albo nadpisuje pracę pierwszej osoby, albo dostaje nierozwiązywalny konflikt na pliku, którego nie da się otworzyć w edytorze tekstu, żeby ręcznie zdecydować, co zostaje. Po drugie — koszt miejsca: skoro każda wersja to pełna kopia, historia repozytorium rośnie liniowo z liczbą wersji razy rozmiar pliku, bez żadnej z korzyści kompresji różnicowej, na której Git buduje swoją reputację przy kodzie.
Rozwiązaniem, o którym słyszy większość programistów wchodzących do branży, jest Git LFS (Large File Storage) — rozszerzenie, które trzyma duże pliki binarne na osobnym serwerze, a w samym repozytorium zostawia tylko lekki wskaźnik. To realnie rozwiązuje problem rozmiaru repozytorium: klonowanie projektu nie ściąga już całej historii każdej wersji każdej tekstury. Nie rozwiązuje jednak drugiego problemu — modelu współpracy. Git LFS wciąż zakłada mergowanie i wciąż nie potrafi połączyć dwóch wersji pliku Mayi w jedną. Dwoje artystów pracujących nad tym samym plikiem tego samego dnia wciąż kończy z tym samym konfliktem, tylko przechowywanym gdzie indziej.
Do tego dochodzi coś, czego programista rzadko doświadcza: w VFX historia wersji nie jest archiwum, do którego zagląda się sporadycznie — to aktywna, codzienna przestrzeń robocza. Artysta chce mieć natychmiastowy dostęp do dowolnej wcześniejszej wersji swojego pliku, bez czekania na pobranie jej z zewnętrznego magazynu, i chce mieć absolutną pewność, że w danej chwili tylko on edytuje dany plik — nie dowiedzieć się o tym po fakcie, porównując dwa nieczytelne bloby.
Skoro nie da się bezpiecznie łączyć zmian w plikach binarnych, jedynym niezawodnym rozwiązaniem jest niedopuszczenie do sytuacji, w której dwie osoby edytują ten sam plik naraz — nie naprawiać konflikt po fakcie, tylko uniemożliwić go z góry. To dokładnie model, wokół którego zbudowany jest Perforce: zanim zaczniesz edytować plik, jawnie go „wypisujesz" (checkout), co blokuje go dla wszystkich innych, aż go z powrotem „wpiszesz" (submit). To rozwiązanie mniej eleganckie niż automatyczny merge Gita, ale za to dopasowane do plików, których po prostu nie da się połączyć. Poznasz je dokładnie w następnym rozdziale — razem z odpowiedzią na pytanie, dlaczego to wcale nie oznacza, że Git jest w VFX bezużyteczny (bo do kodu samego pipeline'u wraca w Rozdziale 9).
Następny rozdział pokazuje system zbudowany od podstaw pod dokładnie ten problem — Perforce, z jego modelem checkout/submit i blokowaniem plików, który od dekad jest domyślnym wyborem dla danych produkcyjnych w dużych studiach.