Verziókezelés és ami mögötte van

change kép pixabay.com-ról

A programozás világában vannak olyan eszközök vagy megoldások, amiket csak egy bizonyos réteg használ vagy akár ismer. A többi programnyelven vagy adott szintű feladat esetén nincsen rá szükség. A verziókezelés nem ilyen. Gyakorlatilag a legalacsonyabb szinteken is használunk valamilyen verziókezelő szoftvert hosszú évek óta, és bár a verziókezelés a szoftverfejlesztésből indult ki, más területeken is alkalmazzák, például szöveges dokumentumok verzióinak követésére. Nem azt mondom, hogy ez az első dolog, amivel mindenkinek kezdenie kell egy fejlesztést, de leginkább nem arra kell okot keresnem, hogy miért használjam, hanem arra, hogy miért ne. Utoljára 2011-ben írtam cikket a témában, de azzal ellentétben, ebben a cikkben a verziókezelés szükségességét és értelmét próbálom körüljárni, ezzel motivációt próbálva adni azok számára, akik még mindig azt a kérdést teszik fel, hogy "mi ez és miért kezdjek neki?"

Tartalom

Története

[Tartalom]

Oké, tudom, ez a legunalmasabb rész minden cikkben, hacsak nem vagy történész, de okkal kezdek neki. Tisztázzuk tehát a legelején, hogy ez nem a világ hét csodájának egyike, hanem egy alapvető dolog, ami már nagyon nagyon régóta létezik. Igaz, az idő relatív, de a rohamosan fejlődő I.T. világban közel 50 év igenis rengeteg idő.

  • 1972 - Source Code Control System (SCCS) [Wiki link]
  • 1982 - Revision Control System (RCS) [Wiki link]
  • 1990 - Concurrent Versions System (CVS) [Wiki link]
  • 1995 - Perforce (később Preforce Helix, később Helix Core) [Wiki link]
  • 2000 - Apache Subversion (SVN) [Wiki link]
  • 2005 - Git [Wiki link]
  • 2005 - Mercurial (HG) [Wiki link]
  • 2005 - Team Foundation Server (TFS) [Wiki link]

Mindenek atyja tehát talán az SCSS 1972-ből, de sokan talán csak a CVS-re emlékeznek még. Én magam az SVN-nel kezdtem, aztán jött a Git. Próbáltam keresni 2005 utánról említésre méltó újoncot, de eddig nem találtam. A nyílt forráskódú fejlesztések között a Git igen elterjedt megoldás. Mondhatnám, ma már a szoftverek verziókezeléséről az open source közösségben ez az, ami a legtöbbeknek eszébe jut. Közös néven VCS-ként (Version Control System) lehet még a fogalommal találkozni.

Szokás megkülönböztetni distributed (Pl. Git) és centralized (Pl. SVN) VCS-t. A centralized esetén csak egy távoli szerver van, ahova felkerül a forráskód. A distributed lényege, hogy helyben is megvan az összes verzió és alkalmanként fel lehet tölteni a szerverre is. Ez az újabb, amire leginkább azt lehet hátrányként olvasni, hogy bonyolultabb a működése. Nos, több év Git használat után kijelentem, hogy ennek nagyon csekély a jelentősége.

Mire és miért?

Változások követése

[Tartalom]

  • Mindenek előtt a legelső ok arra, hogy akár Git-et, vagy más hasonló rendszert használj, hogy követni tudd a szoftverben történt változásokat. Kezdetben az ember úgy fejleszt, hogy leül a számítógép elé, megnyit egy fájlt szerkesztésre, majd beleír néhány sort. Ez az állapot akár jó volt, akár rossz, a fejlesztés folytatásával meg fog változni. Ilyenkor egyes állapotokat be lehet csomagolni egy zip fájlba, ugye? Működik ez néhány hetente vagy havonta, de a szoftver már akár percek vagy órák alatt is olyan változásokon mehet keresztül, amiről kiderülhet, hogy valamit elrontott, és vissza kellene állni az eredeti állapotra. Az új programsorokat lehet kommentelni ugyan, hogy miért került bele, de mi a helyzet azzal, ami benne volt, de törölted?

  • Az is nagyon hasznos, amikor egy változást megjegyzéssel láthatsz el, így tudod, miért történt az adott módosítás. Ez alapján egy változásnaplót is összeállíthatsz, amit akár a megrendelőnek, akár a főnöködnek megmutathatsz.

  • Minden egyes állapot saját, automatikusan generált azonosítót kap, amivel hivatkozhatsz rá, de szükség esetén egyedi címkét is rendelhetsz hozzá. Ezek általában verziószámok, így könnyebben megtalálod utólag is bármikor az 1.1.5-ös verziót például, vagy összehasonlíthatsz két verziót, hogy azok között mi változott.

Csapatmunka

[Tartalom]

  • Hangzott már el olyan mondat, hogy "nekem nem kell Git, mert én csak egyedül dolgozom". Tévhit, hogy kizárólag csapatmunka esetén hasznos. Sőt, az én nézőpontom szerint, ahogy azt fentebb írtam, nem is ezt kellene elsődleges előnyként emlegetni. Nem elhanyagolható ugyanakkor, és az is igaz, hogy egész egyszerűen elengedhetetlen abban az esetben, ha előfordulhat, hogy több fejlesztőnek ugyanazt a fájlt kell módosítania.

  • Még csak nem is kell olyan nagyon nagy projekt ahhoz, hogy többen dolgozzanak rajta. Előfordulhat, hogy egy kisebb projekt olyan komponensekből áll, amikhez másfajta hozzáértés szükséges. Például Bash szkriptek, Java nyelv, és akár megjelenítés, stílusok. Persze ilyen esetben viszonylag kicsi annak esélye, hogy egyszerre ugyanazt fogjátok módosítani. Segít viszont abban, hogy akár ugyanabban a fájlban, különböző fejlesztők által elvégzett változtatásokat össze lehessen fűzni, amennyiben automatikusan eldönthető, hogy nem ugyanazt a kódrészletet változtatták ketten. Ha ez megtörténik, akkor némi manuális beavatkozás szükséges.

  • Minden változásról megmondható, kihez tartozik, feltéve, hogy szándékosan nem adjuk ki magunkat másnak, amit a szerver megpróbálhat ellenőrizni akár SSH kulcs alapján. A Git-nél ugyanis tetszőleges névvel és e-mail címmel lehet feltölteni egy módosítást, ahol még a szerző és a beküldő személye is megkülönböztethető.

  • Talán szokatlan módon, de csapatmunkaként nem csak az egy időben több programozó általi fejlesztést értem, hanem azt is, amikor a kódnak változik a tulajdonosa, valaki más örökli a programot. Gondolj csak bele. Minek örülnél jobban? Ha kapnál egy több ezer soros kódot, amiről semmit sem tudni a vázlatos changelog-on és jobb esetben a dokumentáción kívül, vagy ha bármelyik sorról meg tudnád mondani, mikor változott, hogy került oda és miért? Gondoskodni kell arról, hogy a forráskód gondozását más is átvehesse szükség esetén.

  • Ez még akkor is hasznos, amikor azon gondolkozol egy kódrészlet láttán, hogy melyik elődöd készítette azt a förtelmet, majd megnézed, és kiderül, hogy te voltál egy kevésbé jobb napodon, vagy téged vonnak felelősségre valamiért, amit egyértelműen egy elődöd hibázott el.

Milyen projekthez?

[Tartalom]

Ha azon gondolkozol, hogy a te projektednél van-e értelme a verziókezelőknek, a fent leírtak ezt segíthetnek eldönteni, de általában az lesz a válasz, hogy igen. Egy distributed VCS-sel ráadásul külön szerverre sincs szükséged, mégis élvezheted az előnyeit. Van azért néhány eset, amikor valóban felesleges:

  • Csak gyakorolsz, függvényeket próbálgatsz, és ezen kívül nincs semmi célod a kóddal.
  • Hirtelen kell egy megoldás, de soha nem fog ismét kelleni.
  • Csak magadnak fejlesztesz egy pár soros programot, aminek az aktuális állapotáról van mentésed, de soha nem érdekelnek a korábbi állapotok. Felhívom a figyelmet a "pár soros" kódra!

Összességében tehát nem az dönt, hogy a program három soros vagy háromezer, hanem hogy mi a célod vele. Van-e célod vele. Tervezel-e vele hosszabb távra.

Nem kell mindent verziózni

[Tartalom]

Ó... végre egy kis engedmény. Azért ne örülj annyira. Nem csak, hogy nem kell mindent, de nem is szabad mindent.

  • Lesznek olyan, a működéshez szükséges környezetfüggő paraméterek, amiket nem szabad kiadni másnak. Tipikusan ilyen a jelszó, de az is lehet, hogy elkerülnéd, hogy fejlesztői beavatkozás kelljen ahhoz, hogy egy paramétert megváltoztassanak. Ezek olyan konfigurációs fájlba kerülnek, amit nem szabad feltölteni a verziókezelőbe, legfeljebb egy példafájlt olyan instrukciókkal, amiből előállítható a szükséges éles konfiguráció.

  • Ezen kívül vannak olyan fájlok, amik a működés közben állnak elő. Azokat a program hozza létre. Például a felhasználók által feltöltött képek, dokumentumok. Lesznek olyan fájlok is, amik a felhasználóktól függetlenül, pusztán a program működése okán jönnek létre. Ilyenek lehetnek ideiglenes fájlok, hibanaplók vagy akár cache fájlok. Úgy tűnhet, hogy erre felesleges gondolni, hiszen, ha működés közben jönnek létre, akkor fejlesztés közben irreleváns. Valamikor viszont ki is kell próbálnod a programot és ezt a legegyszerűbb ott, ahol az aktuálisan fejlesztett forráskód is van. Ekkor viszont véletlenül feltölthetnél egy naplófájlt is, ami rosszabb esetben jelszót is tartalmazhat. És még ha nincs is semmi kényes információ ezekben a fájlokban, akkor sincs helyük a forráskód mellett!

  • Végül pedig bizonyos fájlok a fejlesztői környezet által keletkeznek, például projekt szintű beállítások. Ezek közül némelyiket akár fel is lehet tölteni, ami általános paramétereket tartalmaz és nem a te konkrét környezeteddel összefüggőeket, különben lehet ping-pongozni a beállításokkal, ahogy mindenki más paramétereket tölt fel minden egyes alkalommal. Nem beszélve a jelszavakról, ha azok is vannak. Elképzelhető, hogy minden fejlesztő tetszőleges IDE-vel dolgozhat, így mindenkinél más fájlok jönnek létre. JetBrains-nél például egy ".idea" mappa kerül a projektbe, de NetBeans-nél egy "nbproject". Ilyenkor figyelni kell arra, hogy valaki mindig naprakészen tartsa ezeket, különben egy régről bent maradt nbproject mappa egy új fejlesztőnek csak problémát fog okozni. Másik lehetőség a teljes mappát gitignore-ba tenni és dokumentálni a szükséges beállításokat.

  • Általában bináris fájlokat nem töltünk fel. Ezek változását nem lehet a követni, így csak annyit látnál úgyis, hogy változott, de hogy miben, azt nem. Persze a program részének tekinthető ikonokat, akár logót fel lehet tölteni, de lehetőleg csak akkora méretben, amekkorában feltétlenül szükséges. Minden más, ami inkább adatként kezelhető, mint hivatkozott dokumentum, letölthető állományok, paraméterként átadva kellene megjelenjenek a programban, és ezek mentéséről külön gondoskodni kell. Ha eleve webes felületen lettek feltöltve, akkor tulajdonképpen az adatbázis, ami "átadja a paramétert".

Git esetén ezeket a kihagyandó fájlokat a ".gitignore" nevű fájlban kell leírni. Nem egyenként, hanem akár több fájlra illeszkedő mintákat alkalmazva.

Érdemes az ilyen fájlokat egy logikus struktúrában lehetőség szerint egy helyen tartani. Ha vannak naplófájlok, akkor lesz egy "logs" mappa, ha vannak feltöltések, akkor lesz egy "uploads" mappa, és lehet cache mappa is a teljesség igénye nélkül. De akár ezeket is lehet tovább csoportosítani ezzel csökkentve azon mappáknak a számát is, amikre figyelni kell. Természetesen, amit a fejlesztői környezeted hoz létre, arra kevés befolyásod lesz.

Kapcsolat a kódminőséggel

[Tartalom]

A verziókezelőnek van célja. Pontosabban neked van célod vele. Ez hatással lesz arra, hogy hogyan írod a programot, különben meg fogod nehezíteni a saját dolgod is, de rosszabb esetben másokét is.

  • Ha a programod logikátlanul van felépítve, és egymástól teljesen eltérő funkciók vannak egy fájlban, gyakrabban történhet meg, hogy a verziókezelő nem tudja eldönteni, két különböző fejlesztő által beküldött változtatás közül melyiket kell megtartania. Tehát gyakrabban kell személyesen beavatkozni, ami több hibához vezethet.

  • Ha az ignorálandó fájlok mindenféle rendszert nélkülözve helyezkednek el a projekt különböző pontjain, nagyobb eséllyel fogsz kihagyni valamit a gitignore-ból.
  • Ha indokolatlanul hosszú sorokat írsz a kódba, nehezebb lesz áttekinteni a változásnaplóban, hogy a soron belül mi változott. Az IDE-k, verziókezelő kliensek vagy webes felületek bár gyakran eltérő színnel jelölik a soron belül változott részt, de ettől még a szemednek keresni kell. Ráadásul minél hosszabb a sor, annál nagyobb az esélye, hogy ketten ugyanazt a sort módosítják. Ez például lehet egy nagyon hosszú tömb definíciója, de akár egy hosszabb HTML kód is. A rövidebb sorok pedig végül nem csak a változások kezelésénél segítenek, hanem áttekinthetőbbé teszik a kódot is. Nem kell persze a ló másik oldalára esni, ahol az egész forrás egy hosszú, függőleges struktúra. Ezt hagyjuk meg az assembly-nek.

  • Mivel minden változtatás látszik, kínos lenne hetente ugyanazt kijavítani, mert a következő változtatás elrontja. Kénytelen vagy jobban átgondolni azt, amit csinálsz, ha erre más motiváció nem lett volna. Azt azért fontos megjegyezni, hogy nincs olyan, aki ne hibázna, aki már úgy született, hogy hibátlan "Hello World" alkalmazással köszöntötte a szüleit. Lesznek olyan kódrészletek, amikre nem vagy büszke, de sosem az a lényeg, hogy milyen volt egy program adott állapotában, hanem hogy azóta milyen változáson ment keresztül. Vagy azért, mert magad ismerted fel a hibát, vagy azért, mert felelős fejlesztőként megfogadtad a tapasztaltabb tanácsát, vagy csak valakiét, aki külső szemlélőként könnyebben észrevette azt. Ez akár egy nyílt forráskódú, GitHub-ra töltött projekt is lehet, ahol aztán tényleg a kíváncsi szemek végtelenje vár.

Kapcsolat más rendszerekkel

[Tartalom]

Emlékszel még az évszámra? 1972. Azóta fejlődik a technika és sok fejlesztői eszköz, webes és nem webes szolgáltatás támogatja vagy igényli is egy verziókezelő létét.

  • JetBrains vagy NetBeans is támogatja a Git-et, SVN-t, de kisebb fájlszerkesztőkhöz is van sokszor plugin
  • A Packagist.org-on Git, SVN vagy Mercurial projekteket lehet beállítani, amiből a letölthető csomagok készülnek a PHP függőségkezelőjéhez, a Composer-hez.
  • Az npmjs.org-on ugyan nem lehet közvetlenül Git-ből feltölteni egy csomagot, de telepíteni van lehetőség Gitből, feltöltéskor pedig a ".gitignore" fájlt is figyelembe veszi.
  • A Docker Hub-on szintén van automatikus build, ami GitHub-ról és Bitbucket-ről képes letölteni a friss verziókat.
  • Szükséged van felhasználói dokumentációra? A Read The Docs három Git szerverről is képes automatikusan letölteni a dokumentáció forrását és elkészíteni belőle a dizájnosabb verziót. Ilyen a GitHub, a GitLab és a BitBucket.
  • Ha valamit nem is lehet közvetlenül verziókezelőből publikálni, A travis-ci.org viszont összeköthető a GitHub-bal, így azon keresztül automatizálható a közzététel.

Add, Commit és Push

[Tartalom]

Nem az a cikk célja, hogy használati útmutató legyen, de erről a három utasításról érdemes pár szót ejteni.

Commit

[Tartalom]

A "commit" egyfajta állapotmentés. Ezek azok az állapotok, amiknek lesz hivatkozható azonosítójuk, és lehet címkéjük. A commithoz megjegyzést lehet és kell is fűzni. Ebből látszik ránézésre, hogy mi változott és miért. Érdemes egy rövid mondatban megfogalmazni a lényeget, ami biztos, hogy látszik a változások listázásakor, de mögötte akár részletezni is lehet szükség esetén. Igyekezz összetartozó változásokat elküldeni ilyenkor. Egyszerre több funkción ilyenkor csak akkor változtass, ha azok elválaszthatatlanul összefüggnek. Például az egyik módosítása nélkül a másik sem fog működni.

Soha ne írj olyan megjegyzést, hogy "új változtatások". Ha nem tudod megfogalmazni, mi változott, akkor valószínűleg több dolgot módosítottál. Úgy viszont nehezen fog látszani később, mit, hogyan oldottál meg. Vagy egyáltalán melyik funkció miatt volt szükséges. Szükséges volt-e egyáltalán.

Commitolni lehet bátran sokat. Nem feltétlen baj az sem, ha hiba is becsúszik, bár nyilván az a cél, hogy ez ne történjen meg. Amíg viszont az egyes verziók megfelelően címkézve vannak és a nagyobb fejlesztésekhez, bővítésekhez külön branch-et használsz, ezek nem befolyásolják sem az éles program működését, sem a többi fejlesztő munkáját. A hibát pedig ki tudod javítani. Ha a tökéletes programra vársz egy lépésben, a végén már a kódod 90%-a megváltozik, mire feltöltöd és képtelenség lesz kisebb részekre bontani a változásokat. Persze, ha teljesen használhatatlanul hibás a program, akkor valószínűleg a commit-nak sem lesz értelme.

Add

[Tartalom]

Commit előtt meg kell jelölni azokat a fájlokat, amiket majd szeretnél menteni. Így még ha több változás is történt, de ezek elkülöníthetők egymástól, több lépésben is mentheted. A PHPStorm például már egy fájlon belül is megengedi, hogy az egyes változásokat felvedd a commitba a többi nélkül, de ez nem a Git funkciója.

Push

[Tartalom]

Ez distributed VCS-nél értelmezhető. Git esetén a commit csak a helyi ".git" mappába menti a változásokat. A központi szerverre csak a "push" futtatásakor kerülnek fel. Ez már egy vagy több commitot is tartalmazhat. A már valahol működő, élesített vagy hosszabb távú teszt alatt levő verziót mindig töltsd fel a szerverre, és valamilyen egyedi címkét is érdemes neki adni. Verziószámot például (v1.1.0-beta.2) vagy a közzététel dátumát (2018-04-24). Ez már saját szokásoktól függ. Ha pedig még nem működik sehol, talán csak a saját gépeden teszteled és valami nagyobb javításon, új funkción dolgozol, azt külön branch-ben tedd és a szerveren is külön branch-be töltsd fel. Így az eredeti verziót ennek állapotától függetlenül lehet javítani, később pedig össze lehet fűzni az eredeti ággal a fejlesztést.

Tanulság

[Tartalom]

Levonható a tanulság, hogy a verziókezelő nem csak egy hébe-hóba elővett különlegesség, hanem szerves része a fejlesztésnek és gyakran az üzemeltetésnek. Ha adott pillanatban nem is látod az előnyét a fent leírtak ellenére, biztos lehetsz benne, hogy nem azért épít rá egy nemzetközi közösség apraja-nagyja, mert nincs jobb dolguk. Ha tehát eddig nem használtad, dobd el, ami a kezedben van, és kezdj neki. Persze, ha drága dolog van a kezedben, azt előbb tedd le szépen és vegyél fel valami mást, amit eldobhatsz!

További hivatkozások

[Tartalom]

Megosztás/Mentés

Hozzászólások

Misi képe

Hahó Ákos!
>>"ITHub: Amit tudnod kell fejlesztőként, IV. rész: Verziókezelés " <<
Adsz hozzá linket? Köszi!

Rimelek képe

Szia Misi! Köszönöm a hibajelzést. Elírtam a link "href" attribútumát "hrref"-re, azért nem működött. Javítottam, már kattintható.