A legjobb Git workflow - továbbfejlesztve

Közönségkérésre, most bevezetem az olvasóimat abba a Git repo kezelési módszertanba, amit a saját projektjeimnél használok.

Alapul az egyik talán legnépszerűbb Git workflow szolgált, melynek leírása itt tekinthető meg.

Lássuk az alapfogalmakat, amiket a leírásban használni fogok, ez az én terminológiám:

  • Master branch: A repo alapértelmezett branche. A frissen létrehozott git repo-nál ez a “master” nevű branch, de akárhogy is lehet hívni.
  • Develop branch: Ezen az ágon folyik a fejlesztés, de közvetlenül ide nem commitolunk (lsd. később)
  • Feature branch: egy új feature fejlesztése zajlik rajta. Ez lehet egy új gomb és a mögöttes kód, lehet a tesztek írására szolgáló branch, a lényeg, hogy az itt zajló változások vagy új funkcionalitást adnak a projekthez, vagy annyira jelentősen módosítanak egy meglevő funkcionalitást, ami már nem fér bele a hotfix branchekbe.
  • Hotfix branch: Ide elsősorban hibajavítások jönnek, amelyek jöhetnek valamilyen bugtrackerből, vagy akár bemondásra is, ez már egyéni metodika kérdése. A lényeg: ide olyan változtatás nem küldhető be, mely nagy mértékben változtat a funkcionalitáson.

Szóval. amikor indul a repo életciklusa, akkor létrejön a master branch. A kezdő commit általában vagy egy .gitignore fájl beküldéséből áll (ez a legtöbb esetben hasznos, ha megvan), vagy valami hasonló, jelentéktelen változtatásból. Rails projekt esetében én azt szoktam csinálni, hogy a legenerált és kitisztított projektfát küldöm be, amiben még semmi nincsen, csak a mappák vannak létrehozva, illetve pár dolog felkonfigurálva (pl. rspec, cucumber, meg hasonlók). Mindenesetre az alkalmazás itt kezdi meg életciklusát.

Ez után rögtön le is ágaztatom a develop branchet, majd a develop branchből az első feature branchet. Fontos, hogy minden feature és hotfix branch a develop ágból származik.

A feature branchen elkezdem az első dolgokat implementálni, majd amikor az első feature kész (pl. van egy belépő felület), akkor azt rámergelem a develop branchre. A mergelések mindig szigorúan –no-ff kapcsolóval történnek, mert ez biztosítja számunkra azt, hogy a későbbi grafikus megjelenítéseknél jól elkülöníthetően látszódjon, hogy honnét származik a változtatás.

Példa:

1
2
myproject (feature-add-loginform) $ git checkout develop
myproject (develop) $ git merge --no-ff feature-add-loginform

A hotfix branchekkel ugyanígy járok el.

Hogy ne legyen konfliktus merge-léskor, a feature/hotfix brancheket időnként rebase-lem a develop-hoz (csak ahhoz), hogy meglegyenek azok a változások is, amelyeket más branchen követtem el. Ez ugye pl. webalkalmazásnál fontos, hogy ha a dizájnon változás van, vagy a js-hez új funkcionalitás került, akkor azt egy, ettől függelten feature fejlesztése során is tudjam használni (tipikus példa erre az a pont, amikor az átmeneti combobox-okat leváltja egy automatikus kiegészítés alapú megoldás). Ez egyrészt kényelmi okokból fontos, másrészt pedig azért, mert ilyenkor már zajlik a dogfooding, vagyis a saját kód felhasználói szempontból történő tesztelése. Volt már, hogy itt jöttek elő olyan hibák, melyeket sem a tesztek, sem az első kattintgatások nem hoztak ki.

Van néhány olyan eset, amikor közvetlenül a develop ágra commitolok. A legfőbb szempont ilyenkor, hogy ez csak olyan változás lehet, ami nagyon kevés fájlt érint, illetőleg a branchek nagy részének fontos változtatás. Ilyen lehet például a .gitignore fájl felbővítése, ha valaki hirtelen boldog Mac tulajdonos lesz, és a Mac fájlrendszer csodáit (.DS_Store) ki szeretnénk zárni a projektből. De ilyen lehet az is, amikor egy általunk elütést javítunk ki egy nyelvi fájlban, mert erre pl. felesleges lehet egy új branchet szülni. Persze ez a fejlesztő/fejlesztők által követett módszertantól is erősen függhet. Ilyenkor viszont fontos, hogy minden branch értesüljön a változásokról, és rebase-zel maga alá tegye azokat.

Amikor a projekt elérkezett egy milestone-hoz, akkor történik a master branchre mergelés, közvetlenül a develop branch-ről. Ha a projekt olyan, hogy ez szükséges, ilyenkor a master branchen tagelek is (ez főleg azért érdekes, mert pl. a GitHub minden tagelt branch-ből létrehoz egy letölthető forrás csomagot, így ezzel nekem nem kell törődnöm).

A fő szempont a master-nél, hogy itt mindig stabil, minden változtatástól mentes kód legyen, amely bármikor bárhova deployolható, és azonnal működőképes.

Érdekes kérdés, hogy mi legyen azokkal a hotfix típusú változtatásokkal, amelyek a master branchez kellene hogy menjenek, hiszen az éles alkalmazásban van a hiba, ugynakkor a develop ágon már mergelve van egy feature, amit nem szívesen mergelnénk rá a master ágra. Nos, én általában megpróbálok a helyzethez igazodni. Először is, meg kell nézni, hogy az adott hiba előjött-e már a develop ágon, és fixálva lett-e. Ha nem, akkor ez az első lépés, plusz a megfelelő tesztesetek legyártása, hogy a továbbiakban ilyen probléma elő ne fordulhasson. Ha a hiba nem kritikus, a legegyszerűbb megoldás a hiba javítását a következő milestone-ig eltolni. De nyilván vannak kritkus hibák is, lássuk mi a teendő ezekkel.

A legegyszerűbb eset, amikor még nem történt mergelés a develop-ra a master ágra történt mergelés óta, ilyenkor simán át lehet venni a hotfix branch javítását.

Más esetekben meg kell nézni, hogy a hotfix által érintett fájlok milyen mértékben változtak a master-hez képest. Erre a git diff parancs ad lehetőséget. Ha a fájl ettől a változtatástól eltekintve nem változott, akkor a beküldött commit-nak veszem a diff-jét (git diff HEAD..HEAD), majd alkalmazom csak ezt a javítást a master branchre. Ilyenkor a következő mergelésnél figyelni kell, mert konfliktus léphet fel, ezt sajnos egyedileg le kell kezelni.

Egy másik megoldása a problémának, hogy mivel a master ág az gyakorlatilag a develop ág egy snapshot-ja, így abból indítom a hotfix branchet, és mind a két ágra visszamergelem. Ez talán a legegyszerűbb megoldása a problémának - csakhogy tapasztalatom szerint ez az, ami a legritkábban is működik. Ugyanis nincs értelme álmodozni, a master-ről indított hotfix branchek az esetek nagy részében nem illeszkednek a develop ágra, conflict alakul ki, és elég sok nyűg van, mire oda beilleszkedik, plusz utána a master-ra történő mergeléskor megint kialakulhat conflict. Mindenesetre van, ahol ez a megoldás is működik.

Alternatív megoldás lehet még a cherry-pick használata, mellyel egy darab commit-ot tudunk a develop branchből átvenni a masterre, a mergelés kockázata nélkül. Erről még csak hallottam, nincs gyakorlatom vele, hogy milyen százalékban okozhat conflict-ot, illetve hogy a –no-ff merge képes-e elkezelni az átvett commit-ot. Illetve ez is csak akkor működik, ha nincsenek gyökeres változások a develop ágban erre a fájlra nézve.

Amit a commit-okról még érdemes elmondani: én mindig ún. topic commit-okat használok. Ez azt jelenti, hogy mindig igyekszem olyan commit-okat gyártani, amelyek önállóak, és pontosan egy dolgot csináljanak. Tehát ha pl. teszteket írok, és közben születnek javítások is, amelyek a tesztek lefutásához kellenek, nem nyitok mindig új hotfix branchet (mert egy lusta disznó vagyok), hanem a tesztek ágába belerakom a változást is. Mivel a tesztek az appra nézve nem jelentenek funkcionális változást, a javítás viszont igen, így én nem érzem azt, hogy ennek kockázata lenne. Ellenben nagyon fontos ügyelni arra, hogy ilyenkor mindig pontosan azokat a változtatásokat küldjük be, amelyeket azzal a committ-tal javítunk. Ha kell, hunk (ez a változtatások egysége, a diff kimenetében egy, három kukaccal kezdődő sorral szeparált blokk) szinten bontom szét a változásokat. Erre nagyon jó lehetőséget ad a git add parancs -p kapcsolója. Ennek a megoldásnak a legfőbb haszna az, hogy bárhol meg lehet bontani a develop branchet, bárhol le lehet ágaztatni róla egy új branchet, mindig viszonylag konzisztens állapotot fogunk kapni.

Összességében tehát a legfőbb alapelvek:

  • A master branchre lehetőleg csak mergelés történjen, ide közvetlenül (a kezdő commit-tól eltekintve) ne küldjünk semmit.
  • A develop branch-en lehet játszani, de érdemes figyelni a konzisztenciájára
  • Hotfix branchen a működést alapjaiban érintő változtatás nem történhet
  • Mind a hotfix mind a feature brancheket érdemes frissen tartani a develop-hoz képest, hogy ne érjenek minket nagy meglepetések

Véleményeket itt alul lehet írni, ahogy időm engedi reagálni fogok rájuk.

Comments