Vanhojen versioiden tukeminen on melko klassinen ongelma, johon on olemassa loppujen lopuksi aika yksinkertainen ratkaisu. Väärin tehtynä sen kanssa saa hakattua päätä seinään hyvinkin usein, mutta oikein tehtynä se ei tuota juurikaan ylimääräistä päänvaivaa.

Johdanto

Ohjelmiston kehityksen aikana julkaistaan läjäpäin versioita. Jotkut niistä syntyvät bugikorjausten ja toiset uusien ominaisuuksien myötä. Ja jotkut niistä ovat isompia, toiset pienempiä.

Kun ohjelmistosta on julkaistu ensimmäinen versio, alkaa seuraavan kehittäminen. Tai oikeastaan se on alkanut jo sillä aikaa, kun ensimmäistä versiota vasta hiotaan julkaisukuntoon. Joka tapauksessa, edellisen version elinkaari ei pääty siihen, kun seuraavan version elinkaari alkaa.

Sillä aikaa, kun yhtä versiota viimeistellään julkaisukuntoon, seuraavaan versioon tehdään jo kovaa kyytiä uusia ominaisuuksia. Näin nämä versiot kasvavat toisistaan erilleen. Jos (tai oikeastaan kun) viimeistelyn aikana huomataan bugeja, on tietysti järkevää korjata ne samalla myös seuraavasta versiosta.

Tämä pätee laajemminkin eri versioihin. Kun jostakin hyvin vanhasta versiosta löytyy kriittinen bugi, joka on pakko korjata kaikkiin sitä seuraaviin versioihin, täytyy olla olemassa jokin menetelmä, jotta samaa korjausta ei tarvitse tehdä kaikkiin uudempiin versioihin erikseen.

Tätä sanotaan vanhojen versioiden tukemiseksi.

Olennaista on tietää, miten versiointi toimii. [Semanttinen versiointi] soveltuu tähän erityisen hyvin. Siinä versionumero koostuu kolmesta numerosta, jotka on eroteltu pisteillä: <päätaso>.<alataso>.<korjaustaso> (esim. 1.0.0). Päätasolla esitellään uusia ominaisuuksia, jotka eivät ole yhteensopivia edellisen päätason version kanssa. Alatasolla puolestaan esitellään uusia ominaisuuksia, jotka ovat yhteensopivia edellisen alatason version kanssa. Ja korjaustasolla korjataan vain bugeja rikkomatta yhteensopivuutta.

Jos uusin julkaistu versio on 4.23.3430, siitä näkyy heti, että versioita on todella monta. Jos tällaisessa tilanteessa halutaan korjata bugi versiosta 1.0.0 lähtien, versioita näiden kahden version välillä on monta. Eli korjausta ei välttämättä voida eikä varsinkaan haluta tehdä niihin kaikkiin.

Siksi onkin sovittu, milloin minkäkin version tuki loppuu. Usein tukea tarjotaan vain uusimmille päätason versioille (joissakin tapauksissa myös uusimmille alatason versioille).

Uusinta päätason versiota 1 kuvataan numerolla 1.x.x. Oletetaan, että versionumero on 1.0.0. Tästä versiosta korjataan bugi, jolloin uusimmaksi versioksi tulee 1.0.1. Nyt jos tämän version päälle julkaistaan uusi ominaisuus, versionumerosta tulee 1.1.0. Jos taas tästä korjataan bugi, versionumeroksi tulee 1.1.1. Eli nyt 1.x.x tarkoittaa versiota 1.1.1 eikä enää versiota 1.0.0.

Kuva 1: Versionumeron kasvaminen

Päätason versioiden tuen tulee myös luonnollisesti loppua joskus. Yleensä se tapahtuu, kun seuraavasta seuraava päätason versio julkaistaan tai kun on kulunut jokin tietty aika seuraavan päätason version julkaisusta. Tuki ei lopu ihan heti seuraavan päätason version julkaisun jälkeen, koska voidaan olettaa, että uudesta versiosta (esim. 2.0.0) löytyy bugeja ja käyttäjät tarvitsevat aikaa siirtyä uuteen versioon.

Versiot commit-historiassa

Ajatellaan ohjelmiston koko versiohistoriaa yksinkertaisena jonona committeja. Jonon alussa on niin sanottu ”initial commit” ja viimeisenä uusin ominaisuus tai bugikorjaus. Kaikki muut commitit ovat näiden välissä. Samoin kaikkien julkaistujen versioiden tagit osoittavat committeihin näiden välillä. Voidaan siis ajatella, että seuraava versio on aina suoraan jatkoa edelliselle versiolle. Näin se myös aika lailla todellisuudessa menee, kun asiaa katsotaan tästä suunnasta.

Kuva 2: Commitit jonossa

Toisesta suunnasta katsottuna versiohistoria ei ole jono vaan ennemminkin eräänlainen puu, jossa on haaroja, jotka yhdistyvät välillä.

Kuva 3: Commitit eri haaroissa

Huomaa, että edeltävässä kuvassa näkyy sama versioiden välinen jono, vaikka commitit eivät olekaan jonossa. Versiohistoria rakentuu kaikkein luontevimmin tällä tavalla, joten on pelkästään järkevää, että tätä rakennetta ei rikota, kun vanhempaan versioon tehdään muutos.

Jatkevaan vielä jonoesimerkistä. Kun versioiden 1.0.1 ja 2.0.0 väliin lisätään commit ja uusi versio 1.0.2, jono näyttää toimivan niin, että uusi versio tulee mukaan myös kaikkiin sitä seuraaviin versioihin automaattisesti. Ihan näin yksinkertaiselta se ei näytä puurakenteena. On helppo havaita, että uusi versio kulkeutuu kuitenkin kohtuullisen kivuttomasti seuraaviin versioihin yhdistämällä haaroja eteenpäin jotakuinkin samaan tyyliin kuin kudottaessa villasukkaa.

Kuva 4: Bugikorjauksen kulkeutuminen seuraaviin versioihin

Tarvitaan vain haaroja pitämään commitit eri tasoilla ja tageja paikantamaan yksittäisten versioiden sijainnit commit-historiassa.

Kun johonkin versioon tehdään uusi commit ja uusi versio, sen version haara yhdistetään seuraavan version haaraan, se sitä seuraavaan version haaraan jne. Tällä tavoin haarojen yhdistäminen pysyy hanskassa ja git saattaa jopa osata tehdä ne automaattisesti. Kokonaisuus pysyy myös hallinnassa tällä tavalla paremmin.

Sitten, kun jonkun version tuki loppuu, siihen ei enää tehdä muutoksia ja se voidaan jättää välistä haaroja yhdistettäessä. Esimerkiksi jos version 3.x.x tuki loppuu ennen version 2.x.x tukea, haara 2.x.x voidaan yhdistää suoraan haaraan 4.x.x.