Git-versiohallintaohjelmiston käytön alkeita ja käyttötilanteita

Mihin tarvitaan versiohallintaohjelmaa?

Kuvitellaan että opiskelija Uolevi on kehittämässä kunnianhimoista leksikkoprojektia. Kaksi ensimmäistä päivää sujuu hyvin ja projekti etenee mallikkaasti. Kolmantena päivänä hän huomaa että aiemmin toimineet säännöt eivät enää toimikaan muutosten jälkeen. Uolevi ei kuitenkaan muista enää mitä sääntötiedostossa on muuttunut. Ei hätää, Uolevilla on lokaali GIT-versioarkisto (repository), johon hän säännöllisin väliajoin puskee (git add & git commit) tehdyt muutokset. Uolevi vertaa nykyistä versiota aiemmin luotuun revisioon (git diff) ja huomaa nopeasti tekemänsä virheen.

Projekti etenee mallikkaasti ja se alkaa kiinnostamaan myös muita kollegoja. Kollega Antti on python-guru ja haluaisi auttaa omalta osaltaan kehitystyössä. Syntyy tarve hajautetulle kehitystyölle. Uolevilla on GitHub.comissa remote repository jonka Antti kloonaa (git clone) itselleen. Antti alkaa jo samana iltana kehittämään python-koodia ja saa sen kolmelta yöllä valmiiksi. Antti puskee (git add & git commit & git push) omat muutoksensa GitHub.comissa sijaitsevaan repositoryyn. Samana aamuna kun Uolevi herää, hän tarkistaa onko Antti tehnyt muutoksia projektiin. Uolevi hakee remote repositorysta uusimmat muutokset omalle koneelleen (git pull) ja jatkaa kehitystyötä.

Parempi kuvaus ohjelmistojen versioinnista: http://fi.wikipedia.org/wiki/Ohjelmiston_versiohallinta

Versiohallintaohjelmistojen perusteet ja peruskäsitteet (GIT):

Repository:

Repository eli versioarkisto sisältää tiedon kaikista eri versioista (revision) ja versiohaaroista (branches), mitä projektiin on tehty. Kun omaan uuteen projektiin halutaan ottaa versiointi käyttöön, luodaan aluksi uusi repository ja tämän jälkeen lisätään repositoryyn versio, joka pitää sisällään senhetkiset projektitiedostot. Mikäli taas haluamme alkaa kehittämään jo olemassaolevaa projektia josta versiointi löytyy, kloonaamme versioarkiston omalle koneelle.

Revision

Revisio eli versio pitää sisällään projektin senhetkisen tilan. Revisio luodaan kokoamalla ja tallentamalla paketti lokaalisti muuttuneista ja lisätyistä tiedostoista. Aktiivinen kehitysversio on nimeltään HEAD revision (head isolla).

Commit

Kun kehittäjä on saanut valmiiksi ominaisuuden tai joukon uusia ominaisuuksia, voidaan näistä luoda uusi versio. Tämä tapahtuu kommitoimalla muutokset ja lisätyt tiedostot. Commit pitää sisällään esimerkiksi 10 uutta riviä Lexc -tiedostossa ja yhden TWOLC-säännön. Commitin yhteydessä annetaan myös kommentti, joka kuvaa mitä uudessa versiossa on lisätty / muokattu. Esim. "Lexc-tiedostoon lisätty liitepartikkeleita varten uusi osaleksikko". On kehittäjän päätettävissä miten usein uusia versioita luodaan, mutta version olisi hyvä olla looginen ja toimiva kokonaisuus tai korjaus. Samalla versiohistorian muutoksia ja kommentteja selaamalla saa jonkinlaisen käsityksen miten projekti on aikojen saatossa kehittynyt. Jos kehitys tapahtuu hajautetusti, kommentteja lukemalla saadaan jonkinlainen käsitys mitä muutoksia on tehty ja miksi.

Käyttöohjeet ja komennot

Gitin käyttöön kannattaa perehtyä manuaalin kanssa: http://git-scm.com/documentation

Peruskäytöstä on ohjeet kakkoskappaleessa: http://git-scm.com/book/en/Git-Basics

Konseptuaalisesti olennaisimmat tiedot on lyhyesti käyty läpi seuraavassa tutoriaalissa: http://www.sbf5.com/~cduan/technical/git/

Kun GITin perustoiminnot alkavat sujua, kannattaa tutustua seuraavaan ohjesivustoon, joka kuvaa visuaalisesti mitä yleisimmät GIT-komennot tekevät. Tästä ehkä hahmottaa paremmin miten eri toiminnot linkittyvät toisiinsa. http://marklodato.github.io/visual-git-guide/index-en.html

Muistilista yleisistä komennoista: http://jonas.nitro.dk/git/quick-reference.html

Hajautettu kehitys

GIT-työskentely on aina lokaalia, mutta versiotietoja voidaan siirtää eri versioarkistojen välillä.

Uuden version luominen tapahtuu aina lokaalisti:

git status kertoo mitä muutoksia on mahdollista lisätä uuteen commitiin git add -komennolla halutut tiedostot voi lisätä commitiin. Nämä siirtyvät "staging area"-tilaan. git commit -komennolla tilan "staging area" tiedostoista luodaan uusi versio (revision).

Hajautetussa työskentelyssä omat versiomuutokset siirretään toiseen versioarkistoon (esim. toiselle palvelimelle) git push komennolla. Vastaavasti toisesta versioarkistosta haetaan uusimmat versiomuutokset git pull -komennolla. git pull on oikeastaan yhdistelmä git fetch ja git merge -toimintoja.

Monesti kehittäjät saattavat muokata yhtäaikaisesti samoja tiedostoja. GIT osaa git pull -toiminnon yhteydessä yleensä yhdistää muutokset automaattisesti, mikäli muutokset koskevat tiedoston eri osioita (esim. toinen on tehnyt riviin 2 muutoksia ja toinen riviin 2000). Joskus kuitenkin tulee konfliktitilanne, jolloin esim. molemmat ovat muokanneet tiedoston samaa riviä. Tällöin git merge ei onnistu ja konfliktitilanne tulee ratkaista. Tällaista tilannetta varten ohjeet löytyvät alta: http://genomewiki.ucsc.edu/index.php/Resolving_merge_conflicts_in_Git

GIT ja leksikkoprojektit (LEO)

Leksikkoprojektit ovat perusluonteeltaan hyvin samankaltaisia muiden ohjelmointiprojektien kanssa. Molemmissa käsitellään tiedostoja, joissa yhdekin merkin tai rivin muutoksilla on usein suuria muutoksia lopputuloksen toiminnallisuuden kannalta. Tästä syystä GIT - tai jokin muu versiohallintajärjestelmä kuten SVN - on luonnollinen valinta kehityksen apuvälineeksi. Yhden kehittäjän tapauksessa GIT mahdollistaa muutosten seurannan ja aiempiin versioihin palaamisen. Useamman kehittäjän projekteissa GIT helpottaa huomattavasti hajautettua kehitystä ja auttaa välttämään hajautetun kehityksen yleisimpiä sudenkuoppia.

Versionhallinnan hyvät toimintatavat leksikkoprojekteissa

Samoin kuin muussa versionhallintaa käyttävässä kehitystyössä, tulee leksikkoprojekteissakin käyttää hyväksi todettuja toimintatapoja versionhallinnan suhteen.

Versionhallinnasta löytyvien versioiden tulisi olla aina toimivia kokonaisuuksia. Tämä ei tarkoita sitä, ettei versionhallintaan saa commitoida mitään jollei se ole täysin valmis. Tärkeätä kuitenkin on, että versionhallintaan puskettu uusi työsarka ei riko mitään olemassaolevaa ja ennen kaikkea joku muu voi jatkaa työskentelyä saman tiedoston kanssa ilman, että hänen täytyy tehdä mitään omaan työsarkaansa liittymätöntä sinun muutoksillesi. Ohjelmointiprojekteissa nyrkkisääntö on, että versionhallinnasta löytyvän version tulee aina kääntyä ilman virheitä. Ajatusta kuvaamaan sopii hyvin partiolaisten leiripaikkoja koskeva sääntö: leiripaikka jätetään parempaan kuntoon kuin se oli tultaessa. Samalla tavoin repositorioon puskettavan uuden version tulee olla paremmassa kunnossa kuin sieltä työskentelyn alussa noudettu. Joko sitä on yleisesti siistitty, tai sitten se sisältää kaiken vanhan ja edelleen toimivan toiminnallisuuden lisäksi jotain uutta toiminnallisuutta. Vaikka olisitkin lisännyt jotain toiminnallisuutta, ei sillä ole mitään merkitystä jos seuraava kehittäjä joutuu käyttämään ennen oman työnsä alkua tunnin sinun rikkomiesi asioiden korjaamiseen.

Versionhallinnan committien tulee vastata mahdollisia muutostarpeita. Jokaisen commitin tulisi olla vain yksi muutos. Hyviä nyrkkisääntöjä ovat muunmuassa seuraavat: "Jos sen voi jakaa pienempiin osiin, se on liian iso" ja "Jos se sisältää sanan 'ja', se on liian iso". Esimerkiksi commit jonka kommenttina on "muokattu ellatiivin ja ablatiivin käsittely' i-päätteisillä juurilla" on huono. Jos myöhemmin todetaan että ellatiivin käsittelytapa on huono, ei siihen tehtyjä muutoksia voida vetää takaisin vaikuttamatta samalla ablatiivin käsittelyyn. On siis parempi tehdä kaksi erillistä committia.

Aina commitin liian suuri laajuus ei ole aivan yhtä selvää. Tarkastellaan tilannetta jossa kehittäjä muokkaa LEXC-tiedostoon uuden käsittelypolun ellatiiveille ja liittää sen jo olemassa olevaan rakenteeseen. Commit-kommentin voisi ajatella olevan "Lisätty ellatiivin käsittely". Yksi konkreettinen asia, kaikki on siis kunnossa, eikö? Väärin. On tehty kaksi muutosta: (1) lisätty ellatiivit käsitteleviä rivejä ja (2) integroitu ellatiivien käsittely olemassa olevaan rakenteeseen. On parempi toteuttaa muutostyö kahtena eri committina: toisessa lisätään ellatiivit käsittelevät rivit itsenäisenä kokonaisuutena joka ei vaikuta mitenkään projektin toiminnallisuuteen (poislukien foman antama "käyttämätön leksikko" -varoitus) ja toisessa integroidaan ellatiivien käsittely muuhun rakenteeseen. Mikäli myöhemmin huomataan että ellatiivinkäsittelyn lisääminen on rikkonut projektin, on yhden commitin tapauksessa metsästettävä virhettä kahdesta eri paikasta: itse ellatiivit käsittelevät rakenteesta ja toisaalta sen muuhun rakenteeseen integroivasta osasta. Mikäli työ on puskettu kahtena eri committina, voidaan virhe helposti rajata vain toiseen näistä sijainneista.

Älä uudelleenkirjoita historiaa. Versionhallinnan koko kantava ajatus on vanhojen versioiden säilyttäminen. Historian uudelleenkirjoittaminen vanhoja committeja muuttamalla tai poistamalla on huono tapa, eikä sille ole juuri koskaan mitään todellista tarvetta. Poikkeuksen muodostavat vain tapaukset joissa pusket vahingossa repositorioon omat verkkopankkitunnuksesi.

Varsinkin julkisten repositorioiden tapauksessa tuntee kehittäjä monesti tarvetta ylläpitää kuvaa siitä, että hän tekee vain hyvää lopputulosta: siirrytään suoraan tyhjästä lopulliseen ja hyvään. Tämä "tehdään kaikki lokaalisti ja pusketaan vain täydellistä" -menettely on kuitenkin yleisesti ottaen huono ajatus. Säilyttämällä versionhallinnassa erilaisten iteraatioiden muodossa historian siitä miten jokin projektin osa on kehittynyt, voidaan samaa prosessia tarkastella myöhemmin esimerkkinä: "Yritettiin viimeksi X, Y ja Z, mistä X ja Z ei toimineet". Ilman virheiden ja harha-askelten dokumentointia unohtuvat virheet helposti. Kun virhe unohtuu, se toistetaan. Ja täten on aivan suotta tehty useaan otteeseen samaa virhettä monta kertaa ja menetetty kallisarvoista kehitysaika nelikulmaisen pyörän uudelleenkeksimiseen.

Leksikkoprojektien uniikit haasteet

GIT:n käyttö on helpointa ja vaivattominta projekteissa ja tilanteissa, joissa käsiteltäviä tiedostoja on suurehko määrä suhteessa kehittäjien määrään. Pienessäkin olio-pohjaisessa Java-projektissa saattaa helposti olla kymmeniä tai satoja luokkia, joista jokainen on omassa tiedostossaan ja omaa oman uniikin ja muista erillään olevan toiminnallisuutensa. Täten kukin kehittäjä työskentelee kerrallaan muutaman pienen itsenäisen tiedoston kanssa ja tilanteet joissa useampi kehittäjä haluaa samaan aikaan muuttaa samaa tiedostoa ovat harvinaisia.

Mikäli kuitenkin tarkastelemme pientä leksikkoprojektia, on projektin tiedostomäärä todennäköisesti pienehkö suhteessa kehittäjien määrään. Jo pienessä kahden kehittäjän LEXC-projektissa on hyvinkin todennäköistä että lähes jatkuvasti molemmat kehittäjät haluavat muuttaa jotain samasta tiedostosta ja ennen kaikkea samasta itsenäisestä kokonaisuudesta. Tällöin luonnollisesti myös yleistyvät tilanteet, joissa useampi kehittäjä muuntaa samaa riviä tai aluetta samaan aikaan. Tällaiset tilanteet hankaloittavat versionhallintaa, sillä muutoksia täytyy yhdistää jatkuvasti, mikä puolestaa syö kehitysaikaa. Suorien ristiriitatilanteiden lisäksi ongelmia aiheutuu myös leksikoon mahdollisesti syntyvistä loogisista ristiriidoista, joita GIT ei edes itse huomaa, vaan jotka vaativat kehittäjän manuaalista tarkastusta: jokaisen puskun yhteydessä tulee tarkistaa ettei toinen kehittäjä ole muuntanut samalla jotain, johon olet nojannut omissa muutoksissasi.

Toisaalta versionhallinnan käyttämättä jättäminen on harvoin vaihtoehto, sillä se pelastaa projektin niin valtavalta määrältä muita harmeja ja hidastuksia.

Leksikkoprojekteissa saattaakin olla siis paljon tarvetta ja käyttöä GIT:n commit käskyn -p -vivulle, jonka avulla voidaan luoda committeja tiedoston osista kokonaisten tiedostojen sijaan.

Versionhallintaa tukevat työkalut leksikkoprojekteissa

Samoin kuin muissa hajautetun kehityksen projekteissa, myös monen kehittäjän leksikkoprojekteissa on tärkeää ylläpitää tietoa siitä kuka työskentelee minkäkin projektin osa-alueen kimpussa, mitä on tehty ja mitä vielä tarvitsee tehdä. Tässä auttavat mm. GITHubin repositoriokohtainen wiki sekä Issue ja Milestone -työkalut.

Eräs hyvä toimintamalli on luoda GITHubin repositorioon oma kategoria (Label) tekemättä oleville tehtäville, johon lisätään kaikki TODO-listan kohdat itsenäisinä tehtävinä. Tällöin kehittäjä voi merkitä omakseen tietyn tai tiettyjä tekemättä olevia tehtäviä, ja vältytään tilanteilta joissa useampi ihminen tekee samaa asiaa toisistaan tietämättä. Tehtäviä voidaan myös yhdistää merkkipaaluiksi (Milestone), jolloin projektin kehityksen seuraaminen helpottuu ja projektin aikatauluttaminen on helpompaa: voidaan esimerkiksi asettaa tavoitteeksi, että tietyt merkkipaalut on saavutettu tiettyyn päivämäärään mennessä.

Jos projektin tarkoitus on esimerkiksi taivuttaa suomen nomineita niiden sijassa ja luvussa, löydetään heti luonnollisia Tehtäviä sijamuodoista ja luvuista. Tehdään jokaiselle sijalle nominin molempia lukuja varten oma tehtävä, jonka kehittäjät voivat merkitä omakseen. Tällöin työnjako tapahtuu käytännössä itsestään ja samalla saadaan hyvää tietoa projektin etenemisestä. Pienessä esimerkissämme merkkipaaluja voisivat olla "Kaikki monikon sijat" ja "Kaikki yksikön sijat".

Issue-työkalulla voidaan myös hallita helpommin projektin bugeja: Jos kehittäjä A huomaa oman työnsä ohessa että leksikkoprojekti käsittelee tietyn kehittäjän B työsarkaan kuuluvan sanan väärin, on helppoa ja nopeaa tehdä asiasta Issue. Tällöin löydetystä bugista jää dokumentti, eikä se unohdu sähköpostin syövereihin tai työpöydän sadan muun Post-It -lapun sekaan. Myös muut parannusehdotukset hoituvat helpommin samalla tavoin toimimalla.

GITHubin wikissä taas tarjotaa helpon ympäristön koordinoida projektia vapaamuotoisemmalla tekstiaineistolla.

Mikäli projektisi ei ole GITHubissa vaan jossain muualla, on tärkeää varmistaa että projektin ja tehtävien dokumentointi hoidetaan jollain muulla tavoin. Yksinkertaisimmillaan tämä onnistuu esimerkiksi GoogleDocs -palveluun luodulla taulukolla jossa on listattuna kaikki projektin tehtävät, kenen vastuulla ne ovat ja ovatko ne tekemättä, työn alla vai valmiina.

Harjoitus

1. Hipulla on toimiva git-ohjelmisto asennettuna. Kokeile tutoriaalien perusteella luoda omasta harjoitustyöstä GIT-versioarkisto. Onnistuiko tämä ohjeiden mukaan ja tuliko vastaan ongelmia, mitä?

2. Luo tunnukset github.com-sivustolle, ja selvitä hieman minkä takia palvelun käyttö on räjähdysmäisessä lennossa open source -projektien osalta. Luo githubiin uusi versioarkisto. Kokeile hipulla tämän jälkeen kloonata versioarkisto lokaaliksi versioarkistoksi git clone -komennolla. Halutessasi pyydä kaveriakin kirjautumaan githubiin ja anna hänelle oikeudet versioarkistoon. Näin voi testata hajautettua kehitystä.

-- ErkkiIlmariRajakoski - 2013-05-14

Topic revision: r8 - 2013-05-16 - ljleppan
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2018 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback