Versionhallinta ja Git yleisesti

Tutustutaan ensin versionhallintajärjestelmien yleisiin perusperiaatteisiin ja sen jälkeen tarkemmin Git-nimiseen versionhallintajärjestelmään, jota käytämme tällä opintojaksolla.

Huomautus

Tarkoitus ei ole oppia tätä asiaa pelkästään materiaalia lukemalla. Versionhallintaa käsitellään heti kurssin alussa, ensimmäisellä tai toisella luentokerralla. Lisäksi aihe vaatii käytännön harjoittelua koko kurssin ajan.

Jos Gitin käyttäminen on sinulle jo tuttua, voit siirtyä suoraan seuraavaan materiaaliosioon, jossa kerrotaan yksityiskohdat Gitin käytöstä tällä opintojaksolla.

Jos taas olet käyttänyt Gittiä aiemmin, mutta olo on hieman epävarma esim. terminologian suhteen, niin tämä materiaaliosio voi olla kuitenkin ihan selventävää luettavaa.

Lisähuomautus

Jos versionhallinta tai alla oleva teksti tuntuu vaikealta, ei kannata huolestua. Tällä kurssilla ei tarvitse osata versionhallintaan liittyvää teoriaa. Riittää muistaa kolme komentoa (git add, git commit, git push), sillä niitä tarvitset palauttaessasi tehtäviä Plussaan. Näiden komentojen käyttö neuvotaan ensimmäisen palautuksen yhteydessä.

Mikä versionhallinta?

Versionhallinta tarkoittaa sitä, että jostakin projektista tai tiedostosta voidaan tallentaa kullakin ajanhetkellä sen silloinen tila, johon voidaan sitten myöhemmin palata, vaikka tiedostoon tai projektiin tehtäisiinkin mitä tahansa muokkauksia tallennuspisteen jälkeen. Versiohistoria koostuu kaikista näistä tallennuspisteistä siinä järjestyksessä kuin versiot on tallennettu.

Erittäin yksinkertainen esimerkki yhdenlaisesta versionhallinnasta on “kumoa” -toiminto, joka löytyy ainakin alkeellisena toteutuksena melkein jokaisesta teksti- tai kuvaeditorista. Jokainen on joskus piirtänyt vaikkapa Paintilla kuvaa ja todennut, että äsken piirtämäni viiva oli huono ja päätynyt kumoamaan viivan piirtämisen (esim. ctrl + z). Viivan piirtämisen kumoaminen palautti versionhallinnasta edellisen version kuvasta. Tämä on versionhallinnan ydinajatus.

Versionhallintaohjelmisto (version/revision control system) on työkalu, jonka avulla projektin lähdekooditiedostoista voidaan hyvin pienellä vaivalla ylläpitää tällaista versiohistoriaa.

Versiohistorian ylläpitämisen lisäksi versionhallintajärjestelmän avulla voidaan samasta projektista tallettaa useaan paikkaan - esimerkiksi eri tietokoneille - omat versiot, joita voidaan työstää erillään toisistaan.

Toisaalta versiosta on olemassa yleensä pääversio, jonka projektissa työskentelevät ihmiset kloonaavat itselleen. Kun omaan klooniin sitten tehdään muutoksia, muutokset voidaan versionhallintajärjestelmän kautta integroida pääversioon, josta kaikki projektin parissa työskentelevät ihmiset voivat vetää muiden tekemät muutokset itselleen.

Keskustietovaraston ja paikallisen tietovaraston väliset yhteydet

Eli kun halutaan aloittaa työskentely jonkin olemassa olevan, versionhallinnasta löytyvän projektin parissa, täytyy projekti ensin kloonata kokonaisuudessaan omaan työskentely-ympäristöön - eli tämän kurssin tapauksessa etätyöpöydälle. Tätä kloonattua kokonaisuutta kutsutaan paikalliseksi tietovarastoksi (tietoarkisto, repository) tai paikalliseksi repositorioksi - lyhyesti “repoksi”.

Ei niin yllättäen, versionhallinnasta löytyvä yhteinen versio projektista on myös tietovarasto ja sitä kutsutaan keskustietovarastoksi.

Työnkulku versionhallinnan parissa

Tutustutaan tarkemmin työskentelyyn keskustietovarastosta kloonatun paikallisen tietovaraston kanssa.

Työkopio ja paikallinen tietovarasto

Kun paikallisessa tietovarastossa olevia tiedostoja aletaan muokata, eivät tehdyt muutokset tallennu suoraan tähän paikalliseen tietovarastoon, vaan versionhallintajärjestelmä tallentaa muutokset ensin ns. työkopioon (working copy).

Kun olet tyytyväinen tekemiisi muutoksiin, voit itse tallentaa ne paikalliseen tietovarastoosi. Tällöin muodostat paikalliseen tietovarastoosi tallennettuun versiohistoriaan uuden tallennuspisteen, johon voit tarvittaessa myöhemmin palata, vaikka tekisit työkopioon muutoksia tai tallentaisit uusia tallennuspisteitä tämän tallennuspisteen päälle. Tällaista tehtyihin muutoksiin sitoutumista kutsutaan “commit”iksi.

Commiteista muodostuva versiohistoria ei kuitenkaan automaattisesti päivity keskustietovarastoon, vaan jotta paikalliseen tietovarastoon tehdyt muutokset saadaan siirrettyä myös keskustietovarastoon, täytyy muutokset julkaista puskemalla ne keskustietovarastoon (push). Keskustietovarastoon viedyt muutokset ovat sitten näkyvissä kaikille projektin parissa työskenteleville.

Versionhallintajärjestelmien yksi tärkeä etu on siis se, että useampi ohjelmoija voi työstää samaa projektia yhtäaikaisesti. Miten kaverin omasta paikallisesta repositoriosta keskustietovarastoon pusketut muutokset sitten saadaan haettua omalle tietokoneelle, omaan paikalliseen tietovarastoon?

Muutokset voidaan vetää (pull) keskustietovarastosta omaan repositorioon.

Q: Mutta eivätkö useat saman projektin parissa työskentelevät ihmiset voi tehdä ristiriitaisia muutoksia, kerran jokainen työskentelee oman versionsa parissa ja voi mielivaltaisesti puskea tekemiään muutoksia keskustietovarastoon? Esimerkiksi voin omassa tietovarastossani tehdä muutoksia tiedostoon, jonka kaverini on omassa tietovarastossaan poistanut.

A: Kyllä voivat. Vaikeasti selvitettävien ristiriitojen välttämiseksi omat muutokset tulee aika-ajoin puskea keskustietovarastoon ja toisaalta muiden tekemät muutokset tulee aina vetää omaan tietovarastoon ennen kuin omia muutoksia puskee keskustietovarastoon. Tällöin muutosten integroimisessa (merge) mahdollisesti syntyvät ristiriidat (conflict, merge conflict) voi ratkaista turvallisesti omassa paikallisessa repositoriossa ja keskustietovarastoon voi sen jälkeen puskea toimivan version, jossa on kaikki toivotut muutokset.

Git-versionhallintajärjestelmä

Tällä opintojaksolla käytetään versionhallinnan harjoitteluun ja harjoitusten palautukseen Git-nimistä versionhallintaohjelmistoa. Gittiin tutustutaan peruskäyttäjän tasolla, mutta kannattaa pitää mielessä, että myöhemmillä kursseilla perustietämys oletetaan ja sen päälle rakennetaan monimutkaisempia versionhallintajärjestelyjä. Gittiä ei siis kannata ajatella pakkopullana, jota käytetään vain harjoitusten palauttamiseen ja silloinkin niin vähän kuin mahdollista, vaan mieluummin hyödyllisenä, ammattilaisten käyttämänä, työkaluna.

Versionhallinnan merkittävimmät edut saavutetaan projekteissa, joissa työskentelee useampia kuin yksi henkilö. Tämä ei tarkoita sitä, että versionhallinnan käyttö yksilöprojekteissa olisi turhaa. Jos versionhallintaa käyttää järjestelmällisesti omissa projekteissaan, yksi tärkeimmistä saavutetuista eduista on mahdollisuus palata joustavasti projektin vanhempiin versioihin sen jälkeen, kun huomataan että on mokattu pahasti. Tällainen paha moka voi olla esimerkiksi kriittisen tiedoston tuhoaminen vahingossa tai täysin epäonnistunut yritys toteuttaa ohjelmaan jokin uusi ominaisuus. Jos projektin tilasta on tehty kopio versionhallintaan ennen ongelmatilanteen syntyä, on suhteellisen suoraviivaista palauttaa projekti lähtötilanteeseen.

Git on versionhallintajärjestelmänä sangen monipuolinen. Tapa jolla sitä hyödynnetään tällä kurssilla ei ole ainoa ja/tai oikea tapa tehdä asioita, mutta soveltuu kurssin tarpeisiin hyvin. Ei kannata hätääntyä, jos törmää muissa yhteyksissä toisenlaisiin mekanismeihin.

Koska Git on ainakin tällä hetkellä kaikkein muodikkain versionhallintajärjestelmä, sen käytöstä löytää Googlen avulla lähes loputtomasti materiaalia. Katso esimerkiksi:

Linkin takaa löytyvä materiaali on mielenkiintoista kaikille, mutta aivan erityisesti niille, jotka aikovat jatkaa ohjelmistotekniikan opintoja tämän kurssin jälkeenkin. Tällä kurssilla vaadittavat asiat löytyvät kirjan kahdesta ensimmäisestä luvusta.

Lisäksi Plussasta löytyy Git-kurssi:

Tällä kurssilla vaadittavat asiat löytyvät Git-kurssin kahdelta ensimmäiseltä kierrokselta. (Myös Plussan etusivulta pääset Git-kurssin uusimpaan versioon.)

Huomaa, että Gittiä voi käyttää minkä tahansa projektin versionhallintaan, niin kauan kuin projekti muodostuu tiedostoista. Versionhallinta käsitteenä ei ole millään lailla sidoksissa tietokoneohjelmien kirjoittamiseen, vaikka siihen sitä ehkä kaikkein useimmin käytetäänkin. Esimerkiksi tämän kurssin kaikki materiaalit on tallennettu versionhallintaan, mikä on ajoittain osoittautunut pelastukseksi.

Git-työnkulku

Seuraavassa kuvassa on esitetty keskeisin työnkulku (workflow) Gitin kanssa työskenneltäessä. Kuva ei ole missään mielessä kattava, mutta sen avulla tällä opintojaksolla pitäisi selvitä pitkälle, jollei aivan loppuun saakka.

Jos käytät Gittiä komentoriviltä (Terminal), tarvitset seuraavia komentoja:

  • normaaliin työnkulkuun: git add, git commit, git push
  • asioiden perumiseen: git checkout, git reset [eli näitä et välttämättä tarvitse lainkaan tällä kurssilla]
  • toisten tekemien muutosten hakemiseen: git pull.

Komennot on esitetty myös alla olevassa kuvassa:

Komentorivillä käytettävät Git-komennot

Kuvion komennot on esitetty hyvin tiivistetyssä muodossa. Palaamme komentoihin tarkemmin siinä vaiheessa, kun perehdymme komentorivin käyttöön tämän kurssin materiaaleissa.

Jos käytät Gittiä Qt Creatorin kautta, löydät Gitin toiminnot valikosta Tools -> Git seuraavilla nimillä:

  • normaaliin työnkulkuun: Local Repository -> Commit, Current File -> Stage, Remote Repository -> Push
  • asioiden perumiseen: Current File -> Undo Unstaged Changes for file, Local Repository -> Reset, Current File -> Undo Uncommitted Changes for file
  • toisten tekemien muutosten hakemiseen: Remote Repository -> Pull.

Komennot on esitetty myös alla olevassa kuvassa:

Qt Creatorissa käytettävät Git-komennot

Molemmissa kuvissa ensimmäisenä pistää silmään se, että työkopion ja paikallisen tietovaraston välissä on yksi ylimääräinen välivarasto, indeksi. Edellä olevassa materiaalissa puhuttiin työnkulun yhteydessä vain paikallisesta tietovarastosta ja työkopiosta. Git lisää näiden väliin vielä yhden välivaraston - indeksin, jonka merkitystä on selvennetty alempana tarkemmin.

Versionhallinta- ja Git-terminologiaa

Versionhallintajärjestelmiin, ja Gittiin vielä aivan erityisesti, liittyy käsitteitä ja termejä, joita ymmärtämättä on kovin vaikea saada minkäänlaista kuvaa siitä, mitä pitäisi tehdä. Edellä raapaisimme termejä työnkulun yhteydessä, mutta tässä vielä esiteltynä lyhyesti olennaisimmat tarvittavat termit. Esitys on hyvin Git-keskeinen.

Tietovarasto (repository)

Tietovarastolla tarkoitetaan paikkaa, jonne projektin kaikki historiatiedot ja eri versiot on talletettu. Toteutus riippuu täysin käytetystä versionhallintajärjestelmästä, mutta käytännössä tietovarasto on aina jonkinlainen tietokoneen kovalevylle talletettu tietokanta. Ohjelmoija ei projektin edetessä muokkaa tietovarastoa suoraan, vaan sinne talletetaan kopioita projektin kaikkien tiedostojen tilasta/sisällöstä tietyllä ajanhetkellä. Käytönnössä voi ajatella, että tietovarasto on paikka, joka sisältää varmuuskopiot projektin vaiheista.

Keskustietovarasto (central repository)

Keskustietovarasto on tietovarasto (ks. edellinen kohta), joka on kaikkien projektin jäsenten yhteisessä käytössä. Kun joku projektin jäsen tallettaa keskustietovarastoon tiedostoihin tekemänsä muutokset, ne ovat kaikkien projektin jäsenten nähtävillä ja käytettävissä.

Tällä opintojaksolla opiskelijoiden projektien keskustietovarastot sijaitsevat koneella course-gitlab.tuni.fi (ks. kohta Kurssilla tärkeitä verkko-osoitteita). Kun opiskelija lähettää (push) koodiin tekemänsä muutokset keskustietovarastoon, ne ilmestyvät kurssin henkilökunnan nähtäville. Sama pätee myös kääntäen: jos esim. assari tallentaa muutoksia opiskelijan keskustietovarastoon, ne ilmestyvät opiskelijan nähtäville (pull-komennon suorituksen jälkeen).

Paikallinen tietovarasto (local repository)

Paikallinen tietovarasto on projektin jäsenen heti projektin alussa omaan käyttöönsä tekemä (kloonaama) kopio keskustietovarastosta. Paikalliseen tietovarastoon projektilainen voi tallentaa versioita oman työpanoksensa koodiin tuottamista muutoksista ilman, että muut projektin jäsenet näkevät niitä.

Kun paikallinen tietovarasto sisältää sellaisia lisäyksiä/muutoksia/korjauksia, että ne on tarkoituksenmukaista jakaa muiden projektin jäsenten kanssa, suoritetaan push-operaatio, joka lisää paikallisen tietovaraston sisällön keskustietovarastoon muiden käyttöön.

Työkopio (working copy)

Työkopio tarkoittaa hakemistoa (alihakemistoineen), joka sisältää ohjelmoijan henkilökohtaiset kopiot kaikista projektin tiedostoista. Ohjelmoija muokkaa työkopion tiedostoja ja lisäilee siihen tarpeen vaatiessa uusia tiedostoja tai tuhoaa turhia. Aina kun työkopioon on tehty sopiva määrä muutoksia, siitä talletetaan uusi versio paikalliseen tietovarastoon (komennot add  ja  commit).

Indeksi (index, cache, stage)

Indeksi on Gitissä eräänlainen lisävarasto työkopion ja paikallisen tietovaraston välissä. Aina kun ohjelmoija haluaa tallentaa projektin tilasta uuden version paikalliseen tietovarastoon, hänen on ensin päivitettävä halutut tiedostot indeksiin (add-komento). Kun paikalliseen tietovarastoon sitten talletetaan uusi versio (commit-komento), vain ne tiedostot, jotka on päivitetty indeksiin, muuttuvat paikallisessa tietovarastossa. Muut tiedostot säilyvät uudessa versiossa muuttumattomina.

Monissa muissa versionhallintajärjestelmissä kaikki työkopiossa muuttuneet tiedostot päivittyvät myös tietovarastossa, kun uusi versio muodostetaan. Gitin tapa on käyttäjän kannalta joustavampi. Jos esimerkiksi työkopiossa on tapahtunut loogisesti eri kategorioihin kuuluvia muutoksia (vaikka virheiden korjauksia ja uuden ominaisuuden lisääminen), käyttäjä voi muodostaa tietovarastoon kaksi uutta versiota. Ensimmäisessä indeksiin on päivitetty vain virheiden korjauksen seurauksena muuttuneet tiedostot ja toisessa uuden ominaisuuden lisäyksen seurauksena muuttuneet.

Commit (version, revision, snapshot)

Commit on Gitin kanssa asioitaessa hiukan sekava termi, koska se tarkoittaa asiayhteydestä riippuen joko

  • Git-komentoa, jolla tietovarastoon muodostetaan uusi versio projektin tilasta, tai
  • synonyymiä sanalle “versio” tai “tallennuspiste” projektihistoriassa.

Tämän kurssin ohjeistuksessa mahdollisia väärinkäsityksiä pyritään välttämään sillä, että jos puhutaan tietovarastoon talletetusta projektin tilasta, commit on kirjoitettu normaalilla fontilla. Jos taas kyseessä on komento, jolla tietovarastoon saadaan muodostettua uusi versio, kirjoitusasu on vakiolevyisellä fontilla commit. Kurssilla tämä ero saattaa tulla esiin niin harvoin, jos ollenkaan, että edellinen kirjoitusasullinen sopimus voi osoittautua turhaksi. Asia kannattaa kuitenkin sisäistää, ennen kuin lähtee lukemaan englanninkielistä dokumentaatiota verkosta.