Jak myśleć o TouchQuill
Zanim wpiszesz pierwszą komendę, warto złapać trzy idee, na których stoi cały system. Reszta dokumentacji będzie się do nich odwoływać.
1. Treść ma adres, nie nazwę
Każdy plik, drzewo katalogów i commit jest przechowywany pod adresem wyliczonym z jego zawartości (hash BLAKE3). Konsekwencje są praktyczne: identyczna tekstura w dwóch miejscach zajmuje miejsce raz; serwer wysyła tylko obiekty, których naprawdę nie masz; a jeśli cokolwiek przekłamie się w transferze, klient to wykryje, bo hash się nie zgodzi. Nie musisz w to wierzyć na słowo, możesz to policzyć.
2. Binariów się nie merguje, bierze się je na wyłączność
Tekstury, meshe i blueprinty nie mają sensownego merge'a. Zamiast udawać, że mają, TouchQuill wbudowuje lock w sam rdzeń: kto trzyma lock, ten commituje; serwer odrzuci push zmiany w zablokowanym pliku od kogokolwiek innego. Kolejka sprawia, że „czekanie na plik” nie wymaga pisania na Slacku.
3. Zmiana jest ważniejsza niż commit
Commit to techniczny zapis; logiczna zmiana (Change ID, ch-…) żyje dłużej: przetrwa poprawki (amend), zmianę opisu i rebase. Dzięki temu review, locki i historia odwołują się do czegoś stabilnego. Do tego dochodzi dziennik operacji: prawie wszystko da się cofnąć przez tq undo, łącznie z odzyskaniem niezapisanej pracy po omyłkowym restore.
Instalacja i pierwszy commit
Klient to jedna binarka tq (Linux, Windows, macOS). Serwer, tq-server, potrzebny dopiero, gdy chcesz współdzielić pracę.
# Linux: paczka rpm · Windows: instalator · albo build ze źródeł: cargo build --release -p tq-cli
tq init MojaGra echo "asset" > Content/hero.txt tq commit -m "pierwszy asset" tq log # ch-4f2a91 rev:1 pierwszy asset (ty) tq status # co się zmieniło od ostatniego commitu
Pomyłka? Nic straconego:
tq restore # wróć do stanu z ostatniego commitu tq undo # ...a jeśli restore był pomyłką, odzyskaj to, co nadpisał
undo potrafi przywrócić nawet niezacommitowane pliki.Praca z zespołem
tq clone https://vcs.studio.com MojaGra # świeży klon tq login --user ola # pyta o hasło (ustawia je admin) tq push tq pull
Logujesz się po ludzku: nazwą użytkownika i hasłem. Pod spodem serwer wymienia hasło na token sesyjny, którego nigdy nie oglądasz; jawne tokeny (tq login tqt_…) zostają dla CI i skryptów. Tożsamość na serwerze wynika z logowania, nie z tego, co zadeklaruje klient. Dlatego w historii i audycie nie da się podszyć pod kolegę. Push jest zawsze fast-forward: jeśli ktoś Cię wyprzedził, najpierw pull.
Artyści: wszystko klikasz w Studio
Artysta nie musi znać ani jednej komendy. Cała codzienna praca to trzy kliknięcia w aplikacji Studio, a wszystko, co poniżej dzieje się „pod spodem”, robi się samo.
1. Sync
Otwierasz Studio i klikasz Sync. Pobiera najnowszy stan projektu od zespołu. Jeśli studio pilnuje buildów, jednym przełącznikiem bierzesz zamiast najnowszej ostatnią stabilną wersję, taką, która na pewno się otworzy w edytorze.
2. Bierzesz plik do edycji
Zanim ruszysz plik, zaznaczasz go i klikasz Zarezerwuj. Od tej chwili jest tylko Twój, nikt Ci go nie nadpisze. Jeśli ktoś już go trzyma, widzisz kto i jednym kliknięciem wchodzisz do kolejki, a Studio powiadomi Cię, gdy plik się zwolni.
3. Wyślij zmiany
Skończone? Wpisujesz krótki opis i klikasz Wyślij. Studio zapisuje zmianę, wysyła ją na serwer i zwalnia rezerwację, wszystko w jednym ruchu. Następna osoba z kolejki dostaje plik automatycznie.
Przerwa w połowie roboty? Niedokończoną zmianę odkładasz przyciskiem Odłóż na później, bez zaśmiecania historii, i wracasz do niej kiedy chcesz. Wszystkie te kliknięcia to pod spodem te same operacje, które programista robi komendami tq (patrz niżej), tyle że artysta nie musi ich w ogóle widzieć.
Programiści
Osobny channel na zadanie
Task channel dziedziczy stan z main, ale Twoje commity nie ruszają nikogo, dopóki nie skończysz.
tq channel create task/GROM-447 --type task tq channel switch task/GROM-447
Commituj swobodnie, poprawiaj śmiało
amend dokleja poprawkę do ostatniego commitu, reword zmienia opis. Change ID zostaje ten sam, więc nic się nie gubi.
tq commit -m "system dodge"
tq amend # poprawka do tej samej zmianyBądź na bieżąco z main
integrate wciąga zmiany z parenta. Konflikt? Nie zatrzyma Cię, zostanie zapisany, a Ty decydujesz kiedy i jak go rozwiązać.
tq integrate
tq conflicts # co wisi do rozwiązania
tq conflict resolve cfl-a1 --take theirsZamknij zadanie
complete scala channel do parenta i go zamyka. Historia zadania zostaje czytelna.
tq complete
Kierownicy: release i porządek
Release channel z ostrą polityką
Na release nie wchodzą commity z nierozwiązanymi konfliktami, a pushować może tylko wskazany krąg. Polityka mieszka w wersjonowanym pliku. Jej zmiana też przechodzi przez historię.
tq channel create release/1.0 --type release
# tq-channel.toml:
[permissions]
write = ["lead", "server-admin"]
integrate = ["lead"]Spory o locki
Ktoś zostawił lock i pojechał na urlop? Poproś o oddanie, a w razie potrzeby przejmij. Każde takie działanie zostaje w dzienniku audytu, z powodem.
tq lock --request Content/Boss.uasset
tq steal Content/Boss.uasset # wymaga uprawnienia lock.stealReview przed domknięciem
Channel może wymagać zatwierdzeń, zanim complete przejdzie. Recenzenci komentują i dają approve/reject, z CLI albo w panelu WWW. Approve wiąże się z konkretnym stanem: nowy push unieważnia stare zatwierdzenia, żeby nikt nie przepchnął zmian po cichu.
# tq-channel.toml: [review] require-approvals = 2 # recenzent: tq review approve tq review comment "popraw nazwę zmiennej" --path Combat.cpp --line 42
Konflikty pod kontrolą
Konflikty można przypisywać osobom i nadawać im terminy. Nierozwiązane po terminie eskalują. Nic nie ginie w szumie.
tq conflict assign cfl-a1 marta tq conflict defer cfl-b2 --deadline 48h
Kto co zrobił
Dziennik audytu rejestruje działania administracyjne i próby przekroczenia uprawnień. Integralność sprawdzisz jedną komendą.
tq-server audit log --denied tq-server audit verify
CI i buildy
Konto tylko do tego, co trzeba
CI dostaje token PAT ograniczony do konkretnych uprawnień. Nawet jeśli wycieknie, nie zrobi nic ponad swój zakres.
tq-server user pat ci-build --user ci --scopes repo.read,build-flag.set
Buduj i oznaczaj
Po udanym buildzie CI ustawia flagę na rewizji. To jest sygnał „ta wersja działa”.
tq build-flag set --rev rev:128 --flag ci --state ok
Zespół bierze stabilne
Artysta nie musi trafić na zepsuty commit programisty: get stable pobiera ostatnią rewizję ze wszystkimi wymaganymi flagami na zielono.
tq get stable
Channele
Channel to linia pracy, odpowiednik brancha, ale z typem i polityką. Typ niesie sensowne domyślne zachowania: na release nie wejdzie commit z konfliktem, task ma właściciela i cykl życia (create → integrate → complete), personal to Twoja piaskownica.
Wart poznania jest channel wirtualny: widok na wycinek repo. Zespół grafików może dostać samo Content/, kod dla nich „nie istnieje”, ale ich commity trafiają do wspólnej historii, z zachowaniem plików, których nie widzą.
tq channel create widok --type virtual --include "Content/..." --exclude "Source/..."
Do pracy na wycinku dużego repo służy też sparse checkout: pobierasz i materializujesz tylko pasujące ścieżki, a reszta nie schodzi w ogóle na dysk. Artysta postaci nie musi ściągać wszystkich map.
tq clone https://vcs.studio.com Gra --sparse "Content/Characters/...,Content/Shared/..."
tq sparse set "Content/Characters/..." # zawęź/poszerz w istniejącym klonie
Locki
Model jest prosty: jeden właściciel, reszta w kolejce. Lock ma timeout bezczynności (domyślnie 4 h). Jak zapomnisz zwolnić i pójdziesz do domu, system nie zablokuje zespołu na noc. Możesz poprosić właściciela o oddanie (--request) albo przekazać lock konkretnej osobie (--give).
Serwer egzekwuje locki przy push: jeśli polityka channela mówi, że *.uasset wymaga locka, push zmiany bez locka zostanie odrzucony z czytelnym komunikatem. Praca offline też jest przewidziana: deklarujesz lock lokalnie, a po powrocie system synchronizuje; jeśli dwie osoby wzięły ten sam plik offline, powstaje spór, który blokuje obie strony do decyzji leada. Nikt nikomu cicho nie nadpisze pracy.
Konflikty
W większości systemów konflikt to ściana: merge staje, a Ty rzucasz wszystko, żeby go rozbroić. W TouchQuill konflikt to zapisany obiekt (cfl-…) z pełnym kontekstem: obie wersje, wspólny przodek, kto i kiedy. Integracja przechodzi zawsze; konflikty rozwiązujesz, kiedy masz na to przestrzeń, albo deleguje je lead.
tq conflict resolve cfl-a1 --take theirs # przyjmij ich wersję tq conflict resolve cfl-a1 --merge # scal pluginem (jeśli format ma differ)
Change ID
Hash commitu zmienia się przy każdej poprawce, Change ID nie. To rozróżnienie brzmi subtelnie, ale w praktyce oznacza, że komentarz z review „popraw to w ch-4f2a91” pozostaje trafny po Twoim amend i rebase. Historia operacji (tq op log) dopełnia obraz: każda operacja zostawia ślad i większość da się cofnąć.
Lens
Klasyczny blame odpowiada na pytanie „kto zmienił linijkę 40 w pliku X”. Lens odpowiada na pytanie, które naprawdę zadajesz: „co się działo z tą funkcją?”, także wtedy, gdy plik zmieniał nazwę, a funkcja wędrowała między modułami. Obejmuje to też Blueprinty Unreala (funkcje, eventy i makra z plików .uasset). Zmiany czysto kosmetyczne (formatowanie, komentarze) nie zaśmiecają wyniku.
tq lens blame --symbol calculate_damage
CREATED ch-6f9 rev:1 krzysztof „pierwsza wersja”
MODIFIED ch-a12 rev:3 marta „buff obrażeń”
MOVED+RENAMED ch-c73 rev:5 krzysztof (compute_damage z Weapon.rs) [~86%]
Symbole wyciąga prawdziwy parser (tree-sitter) dla C++, C#, C, Rust, Pythona, Lua, Go, Javy, JS/TS, z metodami klas i nazwą kwalifikowaną (Enemy::TakeDamage), plus ekstraktor zapasowy dla Verse (UEFN), GDScriptu i shaderów. Dla formatów binarnych jest mechanizm wtyczek (host WASM), a obsługa Blueprintów jest w planach rozwoju. Dopasowanie jest rozmyte: rename razem z edycją ciała dostaje ocenę pewności ([~86%]), a przenosiny rozjechane na kilka commitów w ciągu tygodnia zszywają się w jedną historię. Kiedy heurystyka się waha, oznacza wynik jako niejednoznaczny. Rozstrzygasz sam przez tq lens link, albo w Studio jednym kliknięciem. tq lens trace pokazuje pełny żywot bytu przez wszystkie nazwy. Pełny opis Lens: języki, dopasowanie i granice →
tq lens blame --json. W planach rozwoju: Lens dla Blueprintów (symbole w grafach i plikach .uasset) oraz wtyczki do pełnego Visual Studio i JetBrains Rider.Dobre praktyki
Kilka nawyków, które w praktyce robią największą różnicę:
- Lock przed otwarciem, nie przed zapisem. Najczęstszy scenariusz utraty pracy to godzina edycji pliku, do którego lock ma kto inny. Wyrób odruch: binarka → najpierw
tq lock. - Wymuś locki polityką, nie kulturą. Wpisz
require-lock-for = ["*.uasset", "*.fbx"]dotq-channel.toml. Ludzka pamięć zawodzi, serwer nie. - Commituj często, to nic nie kosztuje. Przy magazynie adresowanym treścią commit dużego repo to milisekundy, a każdy commit to punkt, do którego można wrócić.
- Shelf zamiast commitów „wip”. Niedokończona praca nie musi brudzić historii channela. Shelf ma TTL i można go udostępnić do pary oczu.
- Jedno zadanie, jeden task channel. Male channele integrują się łatwo. Wielotygodniowy kombajn będzie bolał w każdym systemie kontroli wersji.
- CI ustawia flagi, zespół bierze
get stable. To najtańszy sposób, by artyści nigdy nie trafili na zepsuty build. - Konflikt przypisz albo odłóż, nie zostawiaj „na wisząco”.
assign/deferz terminem sprawiają, że konflikty mają właściciela i deadline, a eskalacja zadziała sama. - Na maszynach deweloperskich włącz fsmonitor.
tq fsmonitor startraz na sesję i status/commit przestają zależeć od rozmiaru drzewa. Działa na Linuksie i Windowsie.
Migracja z Git i Perforce
Obie migracje zachowują historię: autorów, czasy, wiadomości. Change ID są wyliczane deterministycznie ze źródła, a Lens działa na zaimportowanej historii od pierwszego dnia. Sensowna kolejność: zmigruj kopię repo, zweryfikuj, przełącz zespół, a stare repo zostaw w trybie tylko-do-odczytu na okres przejściowy.
tq migrate from-git --repo /sciezka/repo --branch main tq migrate from-p4 --port perforce:1666 --user krzysztof --path //depot/... tq migrate verify --repo /sciezka/repo
Przejście dużego studia nie musi być skokiem na raz. Po pierwszym imporcie tq migrate p4-sync dociąga wyłącznie nowe changelisty z Perforce. Na czas migracji P4 zostaje źródłem prawdy, a TouchQuill go mirroruje.
Serwer i uprawnienia
Serwer wystawia gRPC (klienci), REST (integracje) i SSE (live feed zdarzeń). Uwierzytelnianie włącza się z pierwszym dodanym użytkownikiem. Wcześniej działa tryb otwarty, wygodny na testy.
tq-server --data /var/tq --listen 0.0.0.0:7470 --tls-cert cert.pem --tls-key key.pem tq-server user add krzysztof --role developer
http://serwer:7480/admin. Logujesz się hasłem i masz w jednym miejscu użytkowników (dodawanie, role, hasła, PAT-y), przegląd repozytoriów (historię rewizji, channele, locki z kolejkami i konflikty) oraz dziennik audytu z przyciskiem weryfikacji hash-chaina. Jest też przeglądarka repozytorium (drzewo plików dowolnej rewizji, podgląd treści i diff), dostępna dla każdego z prawem odczytu, bez klonowania. Te same uprawnienia co w CLI; każda zmiana ląduje w audycie.Siedem ról wbudowanych (od viewer po server-admin), custom role przez klonowanie z odjęciem uprawnień, ograniczenia ścieżek dla kontraktorów („tylko Content/Weapons/..."), tablica protections w stylu Perforce (reguły per repo × ścieżka, np. „artyści nie zapisują do Content/Code/..."). Reguły odczytu działają też na transferze: plik, którego nie wolno Ci czytać, po prostu nie zejdzie na dysk. PAT-y ze scope'ami dla automatów, override per channel, a przy logowaniu hasłem: polityka złożoności, blokada po serii nieudanych prób i opcjonalne 2FA (TOTP).
Skalę obsługuje się stopniowo, bez przepisywania. Małe studio startuje na jednym pliku (SQLite) i kopii katalogu raz dziennie. Większe przełącza metadane na PostgreSQL (jedną zmienną środowiskową, dane w CAS zostają bez zmian), a zdalne biuro stawia Edge Proxy: read-through cache obiektów w lokalnej sieci. Do tego replikacja na regiony (locki zostają na primary, jedno źródło prawdy), mTLS między serwerami, kopie zapasowe jedną komendą i podpisane cyfrowo wydania.
Referencja komend
| Komenda | Opis |
|---|---|
tq init / clone / setup | utwórz / sklonuj / skonfiguruj repo |
tq login --user / remote | logowanie hasłem (tokeny dla CI), adres serwera |
tq add / edit / status / diff | zmiany w worktree |
tq commit / amend / reword | zapis rewizji (Change ID stabilny) |
tq log / show / cat / restore | historia i nawigacja |
tq rebase / revert | przebazowanie / rewizja-odwrotność |
tq op log / undo / redo | dziennik operacji i cofanie |
tq channel … | create / switch / list / policy |
tq integrate / complete | integracja i domknięcie channela |
tq lock / unlock / locks | locki z kolejką, request / give |
tq conflict(s) … | resolve / assign / defer |
tq shelf … | odkładanie pracy, udostępnianie, TTL |
tq lens blame / trace / symbols | historia i pełny lineage symbolu |
tq lens link / reindex / index | ręczne zszycie, przebudowa i domiar indeksu |
tq review comment / approve / reject | komentarze i zatwierdzenia (bramka na complete) |
tq sparse set / show / clear | praca na wycinku repo |
tq rename | zmiana nazwy repozytorium |
tq build-flag / get stable | flagi buildów i stabilna wersja |
tq workspace … | save / sync / offline / mount / presence |
tq migrate from-git / from-p4 / p4-sync | import historii i inkrementalny mirror z P4 |
tq fsmonitor start / stop / status | demon zmian plików (Linux / Windows / macOS) |
tq notify … | powiadomienia, DND, digest |
tq plugin … | pluginy WASM: extractor / differ |
tq admin obliterate / channel | trwałe usuwanie treści, override uprawnień |
Pełną specyfikację techniczną i decyzje architektoniczne (ADR) udostępniamy na życzenie.