GIT na służbie

Nie jestem zwolennikiem GITa w wersji “sauté”, bo w pewnych zakresach zastosowania sprawia problemy, a sprawia problemy bo ma ograniczenia, a ma ograniczenia, bo napisano go jako rozwiązanie do wersjowania wersji źródłowych kodu przed kompilacją czyli bez binarnych assetów. W czym przejawia się problem z Git’em w wersji klasycznej – dla UE4 potrafi rozsypać projekt (nie jest to reguła, a przypadłość dziejąca się przy dużych assetach pakowanych w repozytorium, typu renderowane filmiki i inne objętościowe rzeczy), jednak do prostych projektów jest zdecydowanie najszybszym rozwiązaniem.

Jak “gitować”? W paru krokach wyjaśnię jak używać Gita – z lekkim wskazaniem na Unreal Engine 4 (ale tylko do małych projektów). To odpowiedź na taki ping “weź mi ustaw gita”, se sam ustaw po tym wpisie, dasz radę.

1. instalujemy

instalujemy sobie albo GitHubDesktop albo git’a do systemu (do skorzystania z linii poleceń terminala) jeżeli mamy MacOS to fajną opcją jest też Sourcetree jako zamiennik GitHubDesktop. Gita możemy już mieć w systemie np. skutkiem instalacji Visual Studio z przyległościami narzędziowymi.

2. zakładamy konto na githubie

Czyli wchodzimy na github.com, zakładamy konto, potwierdzamy maila i “mamy to”.

3. robimy nowe repozytorium

Repozytorium może być prywatne albo publiczne, ma też swoje ograniczenia objętościowe i co do wielkości plików.

4. inicjacja projektu

Z poziomu aplikacji będzie to proste – wskazujemy lokalny (czyli na naszym dysku) katalog repozytorium. Z poziomu terminala – inicjujemy w katalogu naszego projektu repozytorium git komendą:

git init .

zwrotnie dostajemy informację:

Initialized empty Git repository in D:/KatalogNaszegoProjektu/.git/

5. Dodajemy pliki

Najwyższa pora na dodanie naszych plików do repozytorium, służy do tego komenda:

git remote add origin

po której musimy podać adres SSH naszego repozytorium i tutaj zaczynają się schody – w zależności czy masz wygenerowany klucz. Powiedzmy, że nie masz. Do klienta GithubDesktop teoretycznie nie potrzebujesz, ale to oznacza, że zamiast SSH musisz używać HTTPS.

6. klucz SSH

No to dygresja na moment – robimy klucz SSH, potrzeby będzie Twój adres email, a potem bezpieczne hasło do wprowadzenia 2x

ssh-keygen -t ed25519 -C "twoj@adresemail.com"
Generating public/private ed25519 key pair.

Czas na 2x bezpieczne hasło:

Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:\Users\twojuser/.ssh/id_ed25519.
Your public key has been saved in C:\Users\twojuser/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:dlugiciagdziwnychznakow twoj@adresemail.com
The key's randomart image is:
+--[ED25519 256]--+
tutaj jakiś dziwny ASCII art :)
+----[SHA256]-----+

Musimy dodać nasz klucz SSH do konta Github. Stosowna opcja znajduje się w zakładce settings konta GitHub.

The key field

Jak już dodamy klucz, to możemy pobrać adres naszego repo w postaci ssh:

7. dodajemy zdalne repozytorium do naszego

To jest moment w którym wracamy bumerangiem do momentu, gdzie się zatrzymaliśmy w poszukiwaniu klucza SSH czyli komendy:

git remote add origin

uzupełniając ją o skopiowany adres czyli:

git remote add origin git@github.com:tooloudtoowide/naszerepo.git

8. ściągamy repozytorium online

Od razu ściągamy sobie zawartość tego co już jest na repozytorium (to będzie zwykle na początku sam plik readme tworzony automatycznie – oczywiście jeżeli zaznaczyliśmy taką opcję – ten plik readme wyświetla się po wejściu przez przeglądarkę www na stronę naszego repozytorium):

git fetch

Za pierwszym razem musimy potwierdzić połączenie, hasło etc. a jak to już zrobimy to potem idzie to samoczynnie. Jednym z końcowych komunikatów będzie:

Unpacking objects: 100% (5/5), 1.82 KiB | 232.00 KiB/s, done.
From github.com:tooloudtoowide/naszerepo
[new branch] main -> origin/main

9. wybór branchu czyli wątku repozytorium

Bo na początku mamy tylko główny branch (ja określam to jako wątek – można mieć kilka wątków z różną zawartością i wersjami plików). Przełączmy się na niego. Wpisujemy:

git checkout main
Switched to a new branch 'main'
branch 'main' set up to track 'origin/main'.

10. co widzimy czyli git status

Na początek proponuję zobaczyć “co widzimy” jako repozytorium, służy do tego komenda:

git status

zwykle pojawi się też lista rzeczy, które nie są dodane. W katalogu projektu mamy plik (a jeżeli nie mamy to powinniśmy go sobie zrobić – zwykły plik tekstowy o nazwie:

.gitignore

11. Ignorancja to błogosławieństwo

.gitignore to jest plik, w którym przechowywane są wyjątki czyli “czego nie chcemy w repozytorium”. Dla Unreal Engine będą to katalogi:
– binary
– intermediate
– saved
– plugins etc.

Albo może inaczej – tak naprawdę dla Unreal Engine potrzebujemy zachować trzy katalogi:
Config
Content
Source (jeżeli nasz projekt zawiera klasy i kod C++)

i w głównym katalogu pliku .sln (plik Visual Studio dla projektów w C++) i nasz główny plik .uproject

Ja dodałem pliki .png jako regułę pomijania do .gitignore i wyłączyłem ignorowanie plików .sln przez zakomentowanie ich w liście ignorowanych:

#*.sln

#icon or thumbnails
*.png

Reasumując – dodajemy do listy ignorowanych rozszerzeń to co potrzebujemy, to samo odnośnie listy katalogów do pominięcia i robimy ponownie:

git status

Dostajemy zaktualizowaną listę tego co “widzi” git i co nie jest pominięte, a jest np. nieśledzone (niedodane do repozytorium zmian). U mnie wyglądało to po zmianach .gitignore tak:

git status
On branch main
Your branch is up to date with 'origin/main'.
Untracked files:
(use "git add …" to include in what will be committed)
Config/
Content/
Source/
naszprojekt.uproject
nothing added to commit but untracked files present (use "git add" to track)

12. dodanie plików i katalogów do repozytorium

W sumie jest to napisane – nie mamy “śledzonych” czyli dodanych do repozytorium – paru katalogów i paru plików.

Plik .uprojekt zdecydowanie do dodania, trzy kluczowe i podstawowe katalogi projektu w Unreal Engine – też. Wpisujemy więc:

git add .\Config\ .\Content\ .\naszprojekt.uproject .\Source\

… i zapisujemy plik. Tym razem robiąc git status dostałem długą listę dodanych plików (jako new file) taką informację:

Changes not staged for commit:
(use "git add …" to update what will be committed)
(use "git restore …" to discard changes in working directory)
modified: .gitignore

O co chodzi? Zmodyfikowaliśmy plik, jego zmiany nie są śledzone, bo nie jest on w repo online i nie został dodany do zawartości jaką definiujemy jako nasze lokalne repozytorium (które potem zsynchronizujemy z repozytorium online). Czy trzeba użyć powyżej wskazanej komendy git add nazwapliku.

git add .\.gitignore

13. commit czyli proszę mi to zapamiętać

Na koniec – pozostaje nam zatwierdzić aktualny stan repozytorium (czyli tzw. commit). Co to jest ten commit? To komenda sygnalizująca gitowi, że chcemy zapamiętać ten stan plików. Plików które wcześniej określiliśmy jako “śledzone” (tracked). Czyli git sprawdza w których plikach z listy tych dodanych przez nas coś się zmieniło i przygotowuje listę tych zmian do wysłania na serwer. W przypadku pierwszej wrzuty mamy przy plikach informacje ‘new file’, to sytuacja w której dodajemy pliki a nie je modyfikujemy. Commit wysyłamy najlepiej z komentarzem np. co zmieniliśmy albo jaki stan zapamiętujemy (docenicie przy n-tej wrzucie do repo):

git commit -a -m "This is just a beginning"

i co dalej, mamy to? No nie. Mamy to lokalnie. Co dalej? Znowu git status:

git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean

14. push it baby czyli wypchnięcie danych do repozytorium online

I teraz chyba powinno być jasne, po dorzuceniu lokalnie zmian do “commita” musimy zrobić “wypchnięcie” tych danych do repozytorium na GitHubie, ponieważ jesteśmy – zgodnie ze statusem powyżej “o jedną aktualizację do przodu” w stosunku do repozytorium online. Robimy git push.

git push
Enter passphrase for key '/c/Users/naszuser/.ssh/id_ed25519':
Enumerating objects: 40, done.
Counting objects: 100% (40/40), done.
Delta compression using up to 12 threads
Compressing objects: 100% (36/36), done.
Writing objects: 100% (38/38), 38.35 KiB | 1.16 MiB/s, done.
Total 38 (delta 8), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (8/8), completed with 1 local object.
To github.com:tooloudtoowide/naszprojekt.git
cef9........140c main -> main

Uff, jeżeli wejdziemy teraz do repozytorium na GitHubie, to mamy nasz projekt zaktualizowany.

15. zmiany do zmian

W dalszym trybie użytkowania gita wykonujemy tak naprawdę głównie dwie rzeczy:

git commit -a -m "Ups I did it again in naszprojektgameinstance.h"
git push

Czyli oznaczamy kolejny “stan” naszego projektu do zapamiętania zmian w repozytorium i “wypychamy” te zmiany do repozytorium online.

Jeżeli pracujemy sami i tylko dodajemy zmiany to w zasadzie to będą te nasze codzienne komendy, natomiast przy pracy zdalnej z kimś na pewno będziemy też ściągać zmiany:

git fetch

albo

git pull

Może się też zdarzyć, że będziemy musieli cofać pewne zmiany komendą

git restore

albo

git reset

albo przełączać się pomiędzy branchami

git switch

Polecam zajrzenie do dokumentacji:

git help workflows

tam jest dużo więcej niż tutaj napisałem, aczkolwiek – być może udało mi się to napisać w prosty sposób i nie napisałem przy okazji bzdur 🙂

16. one more thing

Jest zawsze “coś” na koniec. Do dużych assetów w naszym repozytorium będziemy potrzebować rozszerzenia Gita o LFS (large file storage). Znajdziecie je tutaj: https://git-lfs.github.com/. Ponieważ jest to troszeczkę większy temat niż “na szybko git” to wrócę do niego za jakiś czas. Może to będzie takie coś “jak gitować z Unreal Engine”.