# Alapok ##### Mit tegyek ha elakadok? Git-ben van egy beépített git help parancs: ``` $ git help <verb> $ git <verb> --help $ man git-<verb> ``` Például a config-al kapcsolatos dolgok: ``` $ git help config ``` De ha csak egy gyors áttekintésre van szükséged: ``` $ git config -h usage: git config [<options>] Config file location --global use global config file --system use system config file --local use repository config file --worktree use per-worktree config file -f, --file <file> use given config file --blob <blob-id> read config from given blob object Action --get get value: name [value-regex] ... ``` #### Repository A Git repository egy olyan mappa, mely Git verziókezelés alatt áll. Tehát az a mappa, ahol van egy .git mappa, az egy git repo. ``` $ ls -al total 20 drwxrwxr-x 4 rlacko rlacko 4096 okt 8 12:59 . drwxrwxr-x 3 rlacko rlacko 4096 okt 7 12:04 .. drwxrwxr-x 5 rlacko rlacko 4096 okt 7 12:46 docs drwxrwxr-x 8 rlacko rlacko 4096 okt 8 16:39 .git -rw-r--r-- 1 rlacko rlacko 17 okt 7 12:09 README.md ``` Csináljunk egy sajátot! Hozzunk létre egy tetszőleges projekt mappát és lépjünk bele ``` $ mkdir projektem $ cd projektem ``` Nézzük meg, hogy mi a helyzet a git-el. Ehhez a `git status` parancsot tudjuk használni. Ez a parancs a jelenlegi git repo-nkról képes információkat kiírni. ``` $ git status fatal: not a git repository (or any of the parent directories): .git ``` Teljesen üres a mappa, még nincs verzió kontroll alatt. `ls -al` -el tudjuk is ellenőrizni, hogy nincsen `.git` mappa. Tegyük verziókontroll alá a `git init` paranccsal. Ez beállítja nekünk a `master` branchet és más alap dolgokat. A branch-ről még később beszélek, de azt jegyezzük meg addig, hogy ide kerülnek a mentéspontjaink egymás után sorban, mint egy fa ága. <div style="text-align:center"><img src="workshop/img/basic-branching.png" alt="Git branch" /></div> ``` $ git init . Initialized empty Git repository in .../projektem/.git/ ``` Ha megnézzük, mostmár van egy .git mappánk ``` $ ls -al total 12 drwxrwxr-x 3 rlacko rlacko 4096 okt 8 16:52 . drwxrwxr-x 12 rlacko rlacko 4096 okt 8 16:49 .. drwxrwxr-x 7 rlacko rlacko 4096 okt 8 16:52 .git ``` Ebben van minden adatunk a git repo-val kapcsolatban. Gyakorlatilag mikor egy távoli git repo-t leszedünk, akkor ezt a mappát kapjuk meg. Ebből ezután a git alkalmazásunk előállítja nekünk a master ág legutóbbi mentéspontját. #### Mentéseink tárolása Egy logikus megoldásnak tűnhet, hogy az egyes fájlok közt csak az eltéréseket tároljuk. Például: ```gyumolcskosar 1. mentés: alma 2. mentés: [1.mentés 1.sora] alma ``` Ez annyiból jó, hogy a tárhellyel spórol, viszont nem gyors. Képzeljünk el egy 1000 commit-ból álló repo-t. Mi történik mikor a legutóbbit lekérjük? Erre egyik megoldás más verziókezelőknél, hogy optimalizálnak és mondjuk 50 mentésenként csinálnak egy teljes mentést, stb. A Git ezt úgy oldja meg, hogy egy mentés az összes fájlt egy az egybe lemásolja. Például egyik mentés alkalmával feltöltök egy 1gb-os videót, majd a következő mentéskor pár bitet átírok, akkor már 2gb-nyi videó lesz a repóban és ha utána egy másik mentésel ki is töröljük, az attól még megmarad. Persze utólag tudunk olyat, hogy visszmegyünk és kitöröljük az adott mentésből. Oké, tehát például mappákba bemásolja a mentéseinket valamilyen módon, de mégis hova? ``` $ tree .git/objects/ .git/objects/ ├── 13 │ └── 46dac32baea8123272f60b6a04227fe3872bdb ... ├── e6 │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 ├── f4 │ └── 5a6ff55496414b573e97064e998f065182eeee ├── info └── pack ``` Mégis mik ezek? A Git tömörítve és hashelve tárolja a fájlokat. A hashelésnek annyi a lényege, hogy a fájl teljes tartalmán átfuttatunk egy algoritmust, mely ezután kiköp egy 0-9a-z szöveget és ha akár 1 bit-et is változtatunk egy fájlon, akkor más lesz a hash-e. Tehát ha valaki elcommitol valamit, akkor azt már más nem tudja megváltoztatni anélkül, hogy változna a hash. Így tudjuk biztosítani a teljes konzisztenciát az elosztott repo-k között. Hash-t láthatunk például a mentéspontjainkon, fájljainkon, stb. Például itt egy ábra, hogy hogyan társítja a git egy commit-hoz a megfelelő fájlokat egy kis pointer mágia keretében. <div style="text-align:center"><img src="workshop/img/commit-and-tree.png" alt="Commit and Tree" /></div> Ennél jobban nem megyek bele a témába, de érdekes olvasmány. #### Változtatások mentése Hogyan néz ki egy mentés? ``` commit c45abc3d64c7840b4088b77d5a60d02198a78854 Author: Rafael László <rlacko99 [AT] gmail.com> Date: Thu Oct 8 17:19:28 2020 +0200 Készítettem egy gyümölcskosarat ``` Van egy commit-nak `commit hash`-e, `készítője`, `létrehozási dátuma`, és `commit üzenete` Na de hogyan készítünk egy mentéspontot? A fájljainknak különböző állapotai létezhetnek egy repo-ban. - Untracked: Ami még nincs verziókontroll alatt - Staged: Ami már verziókontroll alatt van de még nem mentettük el - Unmodified: Amit már elmentettünk és azóta nem változott - Modified: Az a fájl, ami már verziókontroll alatt van és változott. Ezt utánna szintén Stage-be tudjuk tenni Nézzük meg ezen az ábrán és egy példa projekten keresztül: <div style="text-align:center"><img src="workshop/img/git_lifecycle.png" alt="Git Life cycle" /></div> Mi a jelenlegi helyzet a frissen inicializált repo-ban? ``` $ git status On branch master No commits yet nothing to commit (create/copy files and use "git add" to track) ``` Láthatjuk, hogy még nincsenek mentéspontjaink, nincs mit elmentenünk és egyben a git próbál segíteni, hogy hogyan tudunk stagelni valamit. Ezt több helyen is megfigyelhetjük a git-ben. Próbál segíteni ahol csak tud. Vegyünk fel egy új fájlt. ``` echo 'alma' > gyumolcskosar ``` _Itt az `echo` egy olyan parancs volt, mely kiírta nekünk a terminálra azt, hogy "alma", de átirányítottuk egy fájlba a `>` operátorral és mivel nem létezett a fájl, azt létre is hozta._ - Linux magic #01 Újra megvizsgálva a status-t, látni fogjuk, hogy megjelent, de még nincs verziókontroll alatt. ``` $ git status ... Untracked files: (use "git add <file>..." to include in what will be committed) gyumolcskosar nothing added to commit but untracked files present (use "git add" to track) ``` Ahhoz, hogy git alá helyezzük, a `git add <fájl>` parancsot fogjuk kiadni. _Ezek a parancsok mind képesek rá, hogy Unix-os módon több fájlra is kiadhatóak legyenek. Például a `<fájl>` lehet `*.jpg`amivel minden .jpg fájlt kijelölünk a jelenlegi mappában"_ - Linux magic #02 ``` $ git add gyumolcskosar ``` Ezután megjelenik, mint új fájl a git adatbázisában. ``` $ git status ... Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: gyumolcskosar ``` A fájlunk átkerült staged módba és ezt akár el is tudjuk menteni. A mentéshez a `git commit` parancsot tudjuk használni. `$ git commit`-ot kiadva megnyilik a beállított szövegszerkesztőnk és némi információ a leendő mentéspontról. ``` # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch master # # Initial commit # # Changes to be committed: # new file: gyumolcskosar ``` Láthatjuk amit a `git status` parancs írna ki és pár extra segítséget a git-től. A # -el kezdődő sorok kommentek, ezek nem fognak a commit üzenetbe belekerülni. Írjuk be az első sorba, hogy `Készítettem egy gyümölcskosarat`, majd mentsük el a fájlt és zárjuk be a szövegszerkesztőt. ``` $ git commit [master (root-commit) c45abc3] Készítettem egy gyümölcskosarat 1 file changed, 1 insertion(+) create mode 100644 gyumolcskosar ``` A git mikor érzékelte, hogy bezártuk a fájlt, akkor abból kiolvasta a sorokat, ignorálva a #-el kezdődőket és hozzáadta a mentéspontunkhoz, mint üzenet. Ezt láthatjuk is a visszajelzésben. Továbbá megjelent pár további hasznos információ is. Ismételten nézzük meg mi a helyzet a reponkban: ``` $ git status On branch master nothing to commit, working tree clean ``` Mostmár nem szól amiatt, hogy még nincsen mentésünk, továbbá azt is írja, hogy még semmin nem változtattunk, nem tudunk mit elmenteni. Nézzük meg a további két állapotot is amiben lehet egy fájl. Írjuk bele a gyumolcskosar fájlba, hogy `korte` ```gyumolcskosar alma korte ``` Ezután kiadva a `git status`-t: ``` $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: gyumolcskosar no changes added to commit (use "git add" and/or "git commit -a") ``` Látható, hogy mostmár `modified` a fájlunk, mentsük is el, de most picit másképp. A git és általában minden Unix parancsnak áttudunk adni úgynevezett kapcsolókat. Például `git commit -m <message>`. Ez annyit spórol meg nekünk, hogy nem kell szövegszerkesztőt megnyitnia a git-nek mikor új commit-ot készítünk, hanem átrakjuk a parancsot olyan módba, hogy várjon egy szöveget, mint mentéshez kapcsolódó üzenet. Általában logikusak az egy betűs rövidítések: `-m: message, -a: all`, de tudunk hosszabb verziókat is használni, mint `--message, --all`. > Ne felejtsük el először stagelni a mentendő fájljaink egy > `git add <fájl>` parancs kiadásával. ``` $ git add gyumolcskosar $ git commit -m "Raktam bele egy körtét" ``` Készítsünk egy új fájlt `hordo` néven és nézzük mit ír ki a `git status -s` parancs. ``` $ git status -s ?? hordo ``` Ezzel a kapcsolóval képesek vagyunk egy rövidített státuszt lekérni. Stageljük majd pedig commitoljuk el `"Hoztunk egy hordót"` üzenettel. A lépések közt nézzük meg mit ír ki a `git status -s`. Mi van akkor, ha valami fájlt nem szeretnénk verziókontroll alá tenni? Gondolok például a build-ek mappáira vagy egy IDE által generált fájlokra. Hozzunk létre egy `.gitignore` fájlt és egy `jegyzeteim.txt` fájlt. Ezután adjuk ki a `git status` parancsot. Láthatjuk, hogy a `jegyzeteim` fájl megjelent. Most írjuk be a fájl nevét a `.gitignore`-ba. ```.gitignore jegyzeteim.txt ``` Ezt követően adjuk ki újra a `git status` parancsot. Oh, eltünt a fájlunk! Pont ezt akartuk, mostmár nem fogja figyelni a git ha ilyen fájlt készítünk. Mostmár csak stageljük és mentsük el az új fájlunk. `git add .`, `git commit -m "jegyzeteim ignorálása"` #### Fájlok mozgatása A git semmi adatot nem tárol változásokról, csak mentéseket készít, ahogy említettem. Próbáljuk ki, hogy mi történik ha átnevezünk egy fájlt? ``` mv gyumolcskosar gyumolcskosar.txt ``` ``` git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: gyumolcskosar Untracked files: (use "git add <file>..." to include in what will be committed) gyumolcskosar.txt no changes added to commit (use "git add" and/or "git commit -a") ``` Látható, hogy az eredeti fájlt "töröltük" és egy új fájlt vettünk fel a repo-ba. Érdekes, mi lenne ha stagelnénk a változtatásokat `git add .` -al? ``` $ git add . $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) renamed: gyumolcskosar -> gyumolcskosar.txt ``` Most meg már látszik, hogy csak átnevezés történt? A Git képes rá, hogy felismerje a fájlokat és eldöntse, hogy ugyanaz volt a kettő, tehát átnevezés, mozgatás, stb. történt. De nem tudja követni a fájlt, csak látja, hogy jött egy új fájl ami szinte ugyanaz, mint ami törölve lett nemrég. #### Mentési előzmények A Git egyik legjobb parancsa a `git log` a `git status` után és szeretném ha kipróbálnád. ``` commit 80560db1f5a83496b80f1959fbcbae2ccfff320e (HEAD -> master) Author: Rafael László <rlacko99 [AT] gmail.com> Date: Thu Oct 8 21:07:25 2020 +0200 jegyzeteim ignorálása commit 30bf35d36399e484b03090570e13cb95da92ab8b Author: Rafael László <rlacko99 [AT] gmail.com> Date: Thu Oct 8 20:11:58 2020 +0200 Hoztunk egy hordót commit b677a8639193479157f7a576dffe0186b0dbe2c8 Author: Rafael László <rlacko99 [AT] gmail.com> Date: Thu Oct 8 17:33:07 2020 +0200 Raktam bele egy körtét commit c45abc3d64c7840b4088b77d5a60d02198a78854 Author: Rafael László <rlacko99 [AT] gmail.com> Date: Thu Oct 8 17:19:28 2020 +0200 Készítettem egy gyümölcskosarat ``` Itt azt láthatjuk, hogy milyen mentéspontjaink vannak és a hozzájuk tartozó dolgokat, mint a commit hash vagy a üzenet. Picit tegyük szebbé. Adjuk ki az előző parancsot a `--oneline` kapcsolóval. ``` 80560db (HEAD -> master) jegyzeteim ignorálása 30bf35d Hoztunk egy hordót b677a86 Raktam bele egy körtét c45abc3 Készítettem egy gyümölcskosarat ``` Máris csak a lényeget látjuk. Az is látható, hogy csak 7 karaktert kaptunk a hashből. Elég csak pár karakter, hogy beazonosítsunk például egy commitot a hash-ével. [Előző](workshop/1_installation?id=telepítés-és-konfiguráció) | [Következő](workshop/3_branch?id=branch-ek-elágazás)