3. gyakorlat¶
Szerkesztés alatt!
Az oldal további része szerkesztés alatt áll, a tartalma minden további értesítés nélkül többször, gyakran, jelentősen megváltozhat!
Szinkronizálási lehetőségek¶
Remote¶
A "Git Workflow" egy kritikus pontja a távoli és helyi repó szinkronizálása.
Erre a git push
, git pull
és git fetch
parancsok használhatók.
Push¶
A git push
a local repository commit-jait fogja felnyomni a remote repository-ba.
Alapesetben az aktuális branch-en dolgozik, és csak akkor sikeres, ha a remote repository-ban nincs olyan commit (az adott branch-en), ami a local repository-ban ne volna meg.
Vagyis, ha az adott branch-en a push
nem csak kiegészítené a remote repository-t, de valahol conflict-ot okozna, akkor nem csinál semmit, csak jelzi a hibát.
Ha az aktuális branch még csak a local repository-ban létezik, akkor a git push
nem tudja feltolni a commit-okat.
Megmondja viszont, hogy hogyan lehet magát a branch-et beállítani a remote repository-ban:
1 |
|
Feladat: git push
Ha még megvan a múlt heti branch-ed, a közös folyamatok
lokális verziójában, akkor tedd fel a GitLab szerverre.
Ha nincs, akkor klónozd le ismét, csinálj egy új branch-et a saját h
-s azonosítóddal, készíts egy commit-ot (bármilyen tartalommal) és rakd fel.
Fetch¶
A git fetch
a remote repository commit-jait letölti a local repository-ba.
Ennyi.
A referenciák nem lesznek átállítva.
Vagyis, egy adott BRANCH_NÉV branch esetében azt fogjuk látni, hogy két branch-ünk van: egy BRANCH_NÉV nevű és egy origin/BRANCH_NÉV nevű, és ezek esetleg nem ugyanarra a commit-ra mutatnak.
Feladat: git fetch
Add ki a git fetch
parancsot.
A git branch --list
és git branch -r --list
parancsokkal nézd meg, hogy milyen branch-eid vannak.
Branch-ek a local és remote repository-kban
Az origin/
kezdetű branch-ek a remote repository-n nyilvántartott branch-eket mutatják, de abban az állapotban, ahogyan a local repository ismeri őket.
Ha a local repository-ban vannak olyan commit-jaink, amik a remote-ban nincsenek, és ez az egyes branch-eken elágazást okoz, akkor ez a local repóban így lesz mutatva.
Vagyis, a local BRANCH_NÉV a remote origin/BRANCH_NÉV nevű branch referenciák eltérnek, ráadásul a history-jaik valahol el is ágaznak.
A git fetch
után ezeket az eltéréseket (ha vannak) manuálisan kell feloldanunk.
Pull¶
A git pull
a remote repository commit-jait letölti a local repository-ba, és az aktuális BRANCH_NÉV branch esetében megpróbálja a local branch-et a remote verzió alapján frissíteni (vagyis elvégezni egy merge-et).
Ha a BRANCH_NÉV a local verzióig ugyanazokat a commit-okat tartalmazza mint a remote origin/BRANCH_NÉV, akkor egy fast forward merge után a local és remote BRANCH_NÉV referencia összhangban lesz, ugyanarra a commit-ra fog mutatni.
Ha viszont a local és remote branch valahol elágazott egymástól (pl. időközben valaki felrakott pár commit-ot ehhez a branch-hez a remote-ra), akkor egy "rendes" merge művelet történik, ami esetleg egy conflict-tal elakadhat, és ekkor elkezdhetjük helyben helyrehozni az eltéréseket.
Local¶
A Git-tel való munka egyik legfontosabb lépése amikor valamilyen fejlesztés bekerül a main-be. Ez azért lehet problémás, mert a fejlesztési BRANCH_NÉV branch kiágazása óta sok minden más is bekerülhetett a main-be, és ilyenkor csak remélhetjük, hogy a két változáshalmaz minél kevesebb helyen okoz conflict-ot. Két branch irányított összevonásának (a source branch változásainak átvitele a target branch-be) alapvetően két módja van: rebase és merge. Hogy egy-egy adott projektben melyiket használjuk, az döntés kérdése, de akkor ehhez a döntéshez -- legalábbis a main tekintetében -- tartani kell!
Technikailag a main is csak egy branch
Bár a main egy kitüntetett branch, ami a szoftver "fő" aktuális állapotát tartalmazza, technikailag ez is "csak egy branch". A rá vonatkozó alább taglalt műveletek bármely két branch között megvalósíthatók, még akár úgy is, hogy a main az, amit be akarunk vinni egy másik branch-be.
Rebase¶
A rebase az a művelet, amikor egy BRANCH_NÉV branch első main-ből kiágazó commit-ját a main egy másik, az eredeti elágazástól eltérő commit-jára helyezzük át.
Ez általában úgy néz ki, hogy az adott BRANCH_NÉV branch-en kiadjuk a git rebase main
parancsot, vagyis a branch-ünket az aktuális main-ből ágaztatjuk ki.
(A kiágaztatás itt nem a legjobb szó, hiszen ilyenkor a main-nek még nem lesznek külön commit-jai.)
Ha ez sikerült, és nincs conflict, vagy kézzel szépen feloldjuk az összeset, akkor egy olyan állapotunk lesz, hogy a main "tetején" ott vannak a BRANCH_NÉV branch-ből "visszahozott" commit-ok.
Ilyenkor a main-t egy (fast forward) merge segítségével tudjuk "előretekerni", hogy a BRANCH_NÉV commit-jait is tartalmazza.
Merge¶
Ha a BRANCH_NÉV branch-ünk az aktuális main-ből ágazik ki, akkor lehetőségünk van egy úgynevezett fast forward merge-re.
Ilyenkor a main szépen végiglépked a BRANCH_NÉV commit-jain, egészen a BRANCH_NÉV aktuális utolsó commit-jáig, így a main-ben a merge után nem lesz elágazás (legalábbis emiatt a BRANCH_NÉV branch miatt biztosan nem).
A művelet során nincs conflict, hiszen az új commit-sorozat eleve a main aktuális állapotából indul.
A git merge --ff-only ...
kapcsolóval kikényszeríthető ez a viselkedés; ilyenkor ha a fast forward nem lehetséges, nem történik merge, helyette hibaüzenetet kapunk.
Ha mindenképpen szeretnénk látni a commit history-ban, hogy valamit a BRANCH_NÉV branch-ben fejlesztettünk-e (illetve ha fast forward nem opció, például mert a main-en is vannak commit-ok), akkor marad a "rendes" merge.
Ilyenkor a main-ben létrejön egy úgynevezett merge commit, ami a BRANCH_NÉV branch változásait viszi be a main-be (és tartalmazza az esetleges conflict-ok feloldását is).
Ennek a merge commit-nak két őse van, a main és a BRANCH_NÉV branch utolsó commit-jai, így a commit history-ban láthatóvá válik, hogy melyik változás jött a main-ből és melyik a BRANCH_NÉV branch-ből.
A git merge --no-ff ...
kapcsolóval kikényszeríthető ez a viselkedés (és a merge commit) akkor is, ha egyébként a git egy fast forward-dal is meg tudná oldani a szituációt.
Git konfigurálása
A git config merge.ff
beállítás megmutatja, hogy a Git hogyan viselkedik, ha nem mondunk neki semmit a merge típusáról.
Ha nincs beállítva, akkor az alapértelmezett viselkedés az, hogy a Git megpróbál egy fast forward-ot, és ha ez nem lehetséges, akkor egy merge commit segítségével oldja meg a helyzetet.
A beállítás false
értéke esetén meg sem próbálja a fast forward-ot, hanem mindenképpen merge commit-tal dolgozik.
Az only
érték esetén csak egy fast forward merge-et próbál meg végrehajtani.
Egy Git/GitLab workflow¶
A "Git/GitLab Workflow" az a folyamat vagy módszertan, ahogyan a fejlesztés során a Git és/vagy GitLab-ot használjuk. Mi tartozik ebbe bele? Például olyan dolgok, hogy a fejlesztéseket külön branch-ekben végezzük, ezeket hogyan nevezzük el, hogyan hozzuk létre, hogyan kapcsoljuk össze az issue-val, hogyan és mikor merge-elünk (vagy rebase-elünk), stb. Fontos, hogy a workflow-t a projekt, de még inkább a fejlesztő cég/közösség határozza meg, és ha ez megvan, akkor e szerint kell dolgozni!
Most meg sem kísérelünk megismerkedni egy konkrét teljes workflow-val, inkább csak bemutatunk pár lehetőséget.
Issue, branch és merge¶
Az egyik talán legfontosabb kérdés az szokott lenni, hogy ha van egy fejlesztési feladat, akkor azt hogyan dokumentáljuk és végezzük el (egészen odáig, hogy megjelenik a main branch-ben)? A válasz pedig általában az, hogy létrehozunk neki egy issue-t és egy branch-et, a branch-ben dolgozunk, majd ezt egy merge request segítségével merge-eljük a main-be, és lezárjuk az issue-t. Ennek az egyes lépései természetesen manuálisan is megvalósíthatók, de a GitLab (és úgy általában a többi hasonló rendszer is) nyújt némi automatizmust.
A GitLab workflow, legalábbis a fontosabb pontjai:
- Létrehozunk egy issue-t valamilyen fejlesztési feladatra, ez kap egy N sorszámot (issue id).
- Amikor elkezdünk dolgozni rajta, akkor készítünk egy merge request-et hozzá a GitLab felületén keresztül. Ekkor:
- A GitLab automatikusan létrehoz egy N-az-issue-címe-kicsit-átalakítva nevű branch-et,
- Készít egy Draft merge request-et amivel az N-az-issue-címe-kicsit-átalakítva fejlesztéseit tudjuk a main-be átvinni,
- Összeköti az issue-t, a branch-et és a merge request-et.
- Ezek után tudunk az N-az-issue-címe-kicsit-átalakítva branch-ben fejleszteni.
- Ha készen vagyunk, a merge request-ről levesszük a Draft attribútumot.
- A megfelelő jogosultságú fejlesztő jóváhagyja és elindítja a merge-et.
- A GitLab:
- A beállításoknak megfelelően merge-eli az N-az-issue-címe-kicsit-átalakítva branch-et a main-be (már ha nincs conflict, de arról később),
- Ha úgy volt beállítva, akkor törli is az N-az-issue-címe-kicsit-átalakítva branch-et,
- Lezárja merge request-et, és
- Lezárja az N issue-t.
Természetesen mi magunk is létrehozhatunk branch-et, és ahhoz merge request-et, sőt, megfelelő elemek használatával még valamelyest össze is tudjuk kötni ezeket illetve az issue-t, de ilyenkor inkább manuálisan kell gondoskodnunk arról, hogy ezek megfelelő módon összehangoltan legyenek kezelve.
Feladat: saját fejlesztés issue-tól merge-ig
- A Hallgatói Demonstrációs GitLab Szerver
SDP25-SzoftverfejlesztesiFolymatok
csoportja alatt a saját gyakorlatodhoz tartozóSDP25-IBNa1017L-%
alcsoportfolyamatok
projektjében hozz létre egy Saját név felvitele a README.md-be nevű issue-t, és rendeld is magadhoz. - Hozz létre egy, az issue-hoz kapcsolódó merge request-et ("Create merge request" gomb, és utána a merge request létrehozása).
Létrejött egy branch és egy merge request is.
Ha minden rendben ment, a branch nevének kezdete az issue sorszáma lesz.
- Most klónozd a le a repót a
https://hxxxxxx@git-okt.sed.inf.szte.hu/sdp25-szoftverfejlesztesifolymatok/SDP25-IBNa1017L-%/folyamatok.git
formájú megfelelő URL-ről!
Már van egy local repository
Ha még megvan az előző órán klónozott verzió, benne a múlt órai local commit-tal, akkor abban egy git checkout main
paranccsal vissza lehet állni a main branch-re, és egy git pull
paranccsal szinkronizálni lehet a remote repository-val.
- Állj át az előbb létrehozott issue-hoz tartozó branch-re a
git checkout BRANCH_NÉV
paranccsal. - Írd be a nevedet a
README.md
-be a gyakorlatvezető neve után. - Commit-áld a változtatást. (Ezt a staging area-n keresztül tudod megtenni!)
Létrejött egy új commit.
A branch-hez tartozó commit-od egyelőre a local repository-ban van.
- A
git push
parancs segítségével a változtatásodat tedd fel a remote repository-ba!
A Git panaszkodik, hogy valami nincs szinkronban.
Elvileg ezen a branch-en csak te dolgoztál.
Viszont úgy néz ki, hogy a gyakorlatban valaki más is, és meg is előzött a git push
paranccsal.
A probléma gyors megoldása (ha valóban a jó branch-ben próbáltál meg dolgozni), anélkül, hogy itt most elmagyaráznánk (feltéve, hogy az adott BRANCH_NÉV
nevű branch-en a main-hez képest pontosan egy commit-od van):
1 2 3 |
|
A commit fent van a szerveren.
Ezen a ponton a branch-ben történt commit-od fent van a "központi" GitLab szerver Git repójában is.
- A GitLab-on módosítsd a megfelelő merge request-et, vedd le róla a Draft jelzőt. Részedről ezzel kész a fejlesztés: a következő lépés a merge-elés, de a main védett branch, oda DEVELOPER jogokkal nem tudsz írni. Ez a gyakorlatvezető feladata lesz.
Gyakorlatvezetői feladat: egy merge
A gyakorlatvezető ezen a ponton válasszon ki egyet a merge request-ek közül, és jóváhagyás után hajtsa végre azt!
A merge megtörtént.
Ezen a ponton a kiválasztott branch változtatásai beleolvadtak a main-be (egy új, úgynevezett merge commit verzión keresztül), a merge request és a hozzá tartozó issue lezáródott, a branch pedig (ha úgy kértük) törlődött a szerveren.
Gyakorlatvezetői feladat: még egy merge
A gyakorlatvezető ezen a ponton válasszon ki egy másik merge request-et, és próbálja meg végrehajtani azt!
A GitLab conflict-ot jelez, és nem tudja automatikusan végrehajtani a merge-et.
A korábban és a most bevitt változtatás ugyanazt a sort változtatta meg, és a Git ezt a conflict-ot magától biztosan nem tudja feloldani.
A merge megtörtént.
Nos, ez esetben valaki elszúrt valamit. A korábban és a most bevitt változtatás elvileg ugyanazt a sort kellett (volna) hogy megváltoztassa, márpedig a Git ezt a conflict-ot magától biztosan nem tudja feloldani. Ha fel tudta oldani, akkor valamelyik változtatás nem az volt, aminek lennie kellett volna.
Most nézzük meg a merge request-eket és az issue-kat. Elvileg egynek-egynek el kellett tűnnie (lezáródtak), cserébe a többi merge request-nél a GitLab conflict-ot jelez!
Conflict / Resolve¶
A konfliktus feloldása történhet a GitLab felületről, vagy közvetlenül a Git-ből.
Feloldás GitLab-on keresztül¶
Feladat: Conflict feloldása a GitLab felületén
Nézd meg a saját merge request-edet a GitLab-on!
Kell lennie egy olyan gombnak, hogy Resolve conflict
.
Ezt használva oldd fel az ütközést (készíts egy új verziót a README.md
-ből)!
A Te neved és a hallgatótársad neve abc sorrendben legyen az oktató neve után!
Eltűnt a conflict jelzés.
A merge request újra végrehajtható állapotba került.
Gyakorlatvezetői feladat: egy merge
A gyakorlatvezető ezen a ponton válasszon ki egyet a merge request-ek közül, és jóváhagyás után hajtsa végre azt!
Itt a conflict, hol a conflict?
Hacsak nem voltunk nagyon szerencsétlenek az első két merge request megválasztásával, akkor a GitLab a csoport néhány merge request-je esetén újra conflict-ot jelez, de néhányat továbbra is végrehajthatónak mutat. Mi lehet ennek az oka? Mikor jelez, és mikor nem conflict-ot a GitLab ezekben az esetekben?
Feloldás Git-en keresztül¶
Egy Git-es conflict feloldásához nem kell a GitLab (a Git-nek működnie kell GitLab nélkül is).
Először is, a git pull
le fogja húzni a szerverről a repository aktuális állapotát (és a main-t is beállítja az origin/main-re ha az az aktuális branch-ed).
Egyszerűbb lenne a helyzet, ha lenne jogod a main branch-hez: a git merge SAJÁT_BRANCH
main-en való kiadása után lehetőséged lenne feloldani a conflict-okat (módosítani a fájlokat majd a git add
-dal elfogadtatni a merge-elt verziót), majd a git branch --continue
befejezné a merge műveletet.
Ezzel gyakorlatilag a merge commit-ban lenne helyretéve a conflict.
Viszont, mivel nincs jogod a main írására, ezt fordítva kell megtenni: nem a SAJÁT_BRANCH-et kell a main-be belevinni, hanem (először) a main-t kell merge-elni a SAJÁT_BRANCH-be a SAJÁT_BRANCH-en kiadott git merge main
parancs segítségével.
Conflict esetén -- márpedig pont ezért csináljuk -- a merge folyamata megakad.
A git status
megmutatja, hogy melyek azok a fájlok, amik conflict-oltak.
Ezeket a fájlokat egy szövegszerkesztőben megnyitva valami hasonló alakú részekre bukkanhatunk:
1 2 3 4 5 |
|
Az ilyen részeket kell lecserélni a kívánt tartalommal, vagyis azzal a szöveggel, aminek a merge után meg kellene jelennie az adott helyen.
Ha ez kész, az adott fájlokat a git add
parancs segítségével tudjuk elfogadtatni, majd ha minden conflict-ot feloldottunk, akkor a git merge --continue
segítségével befejezhetjük a műveletet, majd az új branch commit-ot a git push
parancs segítségével tudjuk feltolni a szerverre.
Ezen a ponton (ha közben nem történt változás a GitLab repóban) a saját merge request-ünk a GitLab-on ismét végrehajtható státuszba kerül.
Feladat: Conflict feloldása manuálisan a Git-ben
- Frissítsd a main branch-edet a GitLab legújabb verziójára a
git pull
segítségével. - Frissítsd a saját branch-edet a GitLab legújabb verziójára a
git checkout
ésgit pull
segítségével. - Most a saját branch-edbe merge-eld bele a main-t a
git merge
parancs segítségével.
A Git conflict-ot jelez
A Git nem tudja automatikusan feloldani a conflict-ot.
A Git nem jelez conflict-ot
Pech. A Git automatikusan feloldotta a conflict-ot, nincs vele tennivalód.
- Oldd fel kézzel a conflict-ot a
README.md
-ben, és készíts egy új commit-ot (fejezd be a merge-et agit merge --continue
segítségével). - Tedd fel az új verziódat a GitLab szerverre a
git push
segítségével.