Git: perusteet

Osaamistavoitteet

Ensimmäisessä Git-osiossa vahvistat aiempaa versionhallintaosaamista. Opit selittämään versionhallinnan roolin perusteet ohjelmistotyössä. Osiossa kertaan versionhallinan peruskäytön yhden hengen projekteissa: miten uusia versioita luodaan, miten valitaan version sisältö, miten versionhistoriaa tarkastellaan ja miten paikallista tietovarastoa synkronoidaan etätietovaraston kanssa.

Versionhallinta

Ohjelmistotyössä versioinnin rooli on kahtalainen: Halutaan kerryttää ohjelmiston kehittämisen ajalta versioista projektin historiaa sekä muutosten peruuttaminen tarvittaessa. Versionti mahdollistaa koodauskokeilut vaikuttamatta projektiin kokonaisuutena.

Ohjelmoinnissa versionnin avulla voidaan esimerkiksi:

  • Kehittää ohjelmaa eteenpäin ja säilyttää samalla siitä julkaistavia versioita.

  • Jakaa ja synkronoida ohjelmakoodia useamman kehittäjän kesken.

  • Seurata ja valvoa ohjelman kehitystä

  • Vertailla eri versioiden eroja (esimerkiksi tehokkuus)

  • Lisätä ja kehittää ohjelman osia erillään tai osana pääkehitystä.

Versionhallintajärjestelmät on kehitetty tähän käyttöön. Niiden tehtäviin kuuluu:

  • Versioiden tunnisteiden luonti

  • Metatiedon tallennus (esim kuka muutti ja mitä)

  • Versioiden välillä siirtyminen

  • Tiettyjen tiedostoversioiden palauttaminen

  • Erilaisten työskentelyhaarojen toteutus

Versionhallinta ohjelmistotyössä (kesto 20:11)

Git

Git on ohjelmistoalalla laajalti käytetty versionhallintatyökalu. Git-osaamisella toinen laajalti käytetty versionhallintatyökalu Mercurial on varsin suoraviivaista käyttää, vaikka näissä erojakin on. Git on hajautettu versionhallinta. Hajautetussa versionhallinnassa käytössä on samanaikaisesti useita paikallisia tietovarastoja, joilla on yhteinen kehityshistoria. Jokainen paikallinen tietovarasto voi sisältää enemmän ja/tai vähemmän tietoa kuin muut paikalliset tietovarastot. Tästä johtuen paikalliset tietovarastot pitää välillä synkronoida yhteen. Synkronointia varten on yksi keskitetty tietovarasto, jonka kautta käyttäjät synkronoivat paikallisia tietovarastojaan.

Hajautetun vaihtoehtona olisi keskitetty versionhallinta, esim. Subversion. Keskitetyssä versionhallinnassa käyttäjät ovat samanaikaisesti yhteydessä tietovarastoon, jossa versiointia tehdään. Jokainen muutos välitetään suoraan versionhallintapalvelulle, joka välittää muutoksen suoraan muille käyttäjille.

Miten Git versioi tiedostoja?

Yksinkertaistetusti voisi sanoa, että Git tallentaa työpuun sen hetkisen tilan samaan tapaan, kuin kopioisit koko hakemiston. Yksi tällainen tallennettu tilannekuva on versio, josta Gitin yhteydessä käytetään nimitystä commit. Jokainen luotu commit säilyy (lähes) peruuttamattomasti tietovarastossa.

Todellisuudessa asia on hieman monimutkaisempi.

  1. Koko työpuun sisältöä ei tallenneta, vaan ainoastaan tallennettavaksi valitut osat.

  2. Committeihin ei tallenneta kopiota hakemistosta, vaan siihen tehdyt muutokset edelliseen committiin nähden.

  3. Tallennettuihin muutoksin liitetään metadataa ja viite edeltävään committiin.

  4. Versiota ladattaessa työpuun tila luodaan rakentamalla tiedostot historiaketjun pohjalta uudelleen.

Muita huomoioitavia asioita:

  • Kaikki tietovaraston tieto tallennetaan .git -hakemistoon, joka on tyypillisesti työpuun juuressa.

  • .git-hakemistoon sisältö on se, mitä välitetään tietovarastosta toiseen.

  • Kaikki muutokset tallentuvat merkkijonorivien lisäyksinä ja poistoina.

Huomaa!

Työpuu on hakemisto, jonka sisältöä versioidaan. Työpuuhun kuuluvat kaikki tietovarastoon tallennetut tiedostot. Tyypillisesti kaikki tiedostot .git-hakemistoa lukuunottamatta ovat osa työpuuta.

Commit

Commit on Gitissä käytetty nimitys versiolle. Se on tietopaketti, joka koostuu:

Tekijän tiedoista

Nimi, sähköposti, aikaleima

Commitin tekijän tiedoista

Nimi, sähköposti, aikaleima

Viestistä

Tekijän kuvaus commitin sisällöstä

Viittauksesta edelliseen committiin

Mihin versioon tämän version muutokset on tehty

Muutokset työpuussa (blob- ja tree-objektit)

Mitä rivimuutoksia on tehty (blob) ja missä päin työpuuta muutokset sijaitsevat (tree)

SHA-1 tiivisteestä

Commitin tunniste

Versio luodaan kaksivaiheisesti:

  1. Valmistellaan versio eli valitaan muutokset, jotka versioon talletetaan

  2. Versio tallennetaan ja siihen liitetään kuvaus

Versiot valmistellaan indeksiksi kutsutulla alueella. Indeksin valmistelussa valitaan työpuusta halutut tiedostot, joiden sen hetkinen tila tallennetaan nykyiseen versioon. Käyttäjän täytyy siis pitää huoli, ettei tiedostoissa ole mitään ylimääräistä indeksiin lisättäessä ja että työpuussa olevat versiot tiedostoista toimivat juuri halutulla tavalla. Hyvä versio on sellainen pieni selkeitä kokonaisuus, joka tekee yksittäisen eristettävissä olevan muutoksen projektiin.

Gitin käyttö

Gitissä on enemmän toiminnallisuuksia kuin komentoja. Komennot on siis ylikuormitettu, mikä tarkoittaa että komentojen toiminta riippuu annetuista parametreista.

Graafisissa käyttöliittymissä toiminnallisuuksille on yleensä omat erilliset painikkeensa, mutta komentoriviltä ajettaessa ohjaamiseen käytetään mm. vipuja.

Esimerkiksi:
  • git add <tiedosto> lisää vain määritellyn tiedoston indeksiin

  • git add --all lisää kaikki työpuun tiedostot indeksiin (ÄLÄ KÄYTÄ!)

  • git add -p <tiedosto> lisää interaktiivisesti määritellyn tiedoston osia indeksiin.

Gitissä on turvamekanismeja, jotka voivat estää joidenkin komentojen suorittamisen. Mekanismien tarkoitus on suojata historiaa ja paikallisesti tehtyä työtä. Älä ikinä käytä –force-vipua kiertääksesi näitä turvamekanismeja.

Esimerkiksi: Et voi palauttaa vanhaa versiota, jos sinulla on tallentamattomia muutoksia työpuussa, jotka katoaisivat operaation yhteydessä. Sen sijaan voit käskeä palauttamaan tietyn tiedostoversion, vaikka tiedostoa on muokattu.

Näiden kahden tilanteen erona on, että ensimmäisessä muokkausten ylikirjoittaminen olisi halutun toiminnon sivuvaikutus, kun taas jälkimmäisessä toiminnon päätarkoitus on muokkausten ylikirjoitus.

Huomaa!

Kannattaa aina selvittää, miksi Git ei suostu suorittamaan annettua komentoa. Suojamekanismien ohittamisella on usein ei-toivottuja vaikutuksia, kuten historiatietojen tuhoutumista tai korruptoitumista.

Huomaa!

Tiedostoilla on neljä eri päätilaa: committed, modified, staged ja untracked:

  • Committed - Tiedosto vastaa viimeisintä committia.

  • Modified - Tiedostoa on muokattu, mutta muutoksia ei ole tallennettu.

  • Staged - Tiedosto on muokattu ja muokkaukset on lisätty indeksiin.

  • Untracked - Tiedosto on luotu, mutta sitä ei ole versioitu tai valmisteltu versioitavaksi.

Git voi estää joidenkin operaatioiden tekemisen projektin tiedostojen tilasta riippuen.

Tiedon säilyvyys Gitissä

Lähes kaikki Gitin operaatiot lisäävät tietoa tietovarastoon. Jos esimerkiksi poistat tiedoston, Git lisää versiohistoriaan merkinnän “Tästä eteenpäin tiedostoa ei ole”. Myös jokainen tallennettu commit säilyy tietovarastossa pysyvästi, kunhan niihin on pääsy jostain tallennetusta haarasta tai tagista.

Tiedoston olemassaolon pyyhkiminen kokonaan pois versiohistoriasta vaatii historian uudelleenkirjoittamista ja vanhojen committien tuhoamista! ÄLÄ TEE TÄTÄ KEVYIN PERUSTEIN!

Tallennettuun historiaan ei siis kannata koskea, ellei tiedä tarkalleen mitä on tekemässä. Samalla etenkään julkiseen tietovarastoon ei tule pistää mitä tahansa. Ole siis tarkkana, mitä tallennat versiohistoriaan. Tätä varten on tärkeää laittaa tietovaraston .gitignore kuntoon. .gitignore-tiedoston tehtävä on pitää huoli siitä, ettei työpuussa usein oleva kokonaisuuden kannalta ylimääräinen tavara päädy versioiduksi.

Esimerkkejä .gitignoreen:

build-*

Suodattaa pois kaikki polut, jotka alkavat merkkijonolla “build-”

*.o

Suodattaa pois kaikki polut, jotka päättyvät merkkijonon “.o”

local_configurations.py

Suodattaa pois local_configurations.py -nimisen tiedoston.

html/

Suodattaa pois html-hakemiston

!build*.py

Sallii “build” alkuiset polut, jotka päättyvät “.py”, jos nämä suodatettaisiin pois jollain aiemmalla säännöllä.

Yleisin käytäntö on luoda yksi .gitignore -tiedosto työpuun juureen ja määritellä siihen kaikki mitä projekti saattaa generoida tai mitä ei vain haluta versioida.

Mitä Gittiin kannattaa / ei kannata tallentaa?

Git käsittelee tiedostoja tekstimuodossa ja tallentaa rivimuutoksia. Näin ollen tekstitiedostojen, kuten lähdekoodin tallennus, sujuu täysin ongelmitta. Monimutkaisemmat tiedostot, jotka eivät ole sisällöllisesti tekstiä, ovat ongelmallisempia. Näihin tiedostoihin tapahtuvat muutokset aiheuttavat usein sen, että koko tiedosto joudutaan kirjoittaman uudelleen versiohistoriaan. Kyseiset tiedostot ja niiden toistuva muokkaus siis paisuttavat versiohistorian kokoa.

Versionhallintaan ei kannata tallentaa tiedostoja, jotka voidaan täysin generoida muiden tiedostojen pohjalta. Tällöin versionhallintaan kannattaa laittaa vain tiedostot, joiden avulla haluttu tiedosto voidaan luoda. Käytännön esimerkkeinä ovat harvinaisin poikkeuksin käännetty ohjelma, sisällöstä generoituva dokumentaatio tai lokitiedostot.

Mitä kannattaa tallentaa:

  • Toimiva ohjelmakoodi

  • Asetus- ja konfiguraatiotiedostot

  • Dokumentaatio

  • Vaadittu staattinen materiaali

Mitä ei kannata tallentaa:

  • Kääntymätön tai rikkinäinen ohjelmakoodi!

  • Sisällöstä generoituva materiaali (esim. käännetty ohjelma tai käännösprosessissa tuotetut tiedostot)

  • Salasanoja tai muuta tietoturvaa vaarantavaa tietoa

  • Video- ja kuvamateriaalia*

* Poikkeuksena ohjelmien vaatimat materiaalit. Videot, kuvat ja suuret ei-teksti-pohjaiset tiedostot kannattaa kuitenkin tallentaa ja jakaa erillisessä järjestelmässä, jos vain mahdollista.

Peruskäytön Git-komennot

Tärkeää huomio: HEAD on osoitin, joka viittaa siihen committiin jonka päälle nykyistä committia ollaan tekemässä / mihin versioon työpuu on pohjautunut ennen muutoksia.

  • Indeksiin lisääminen voidaan tehdä komennolla git add, jossa parametrina annetaan tiedostopolut, jotka halutaan lisätä indeksiin.

    • git add <polku> Lisää polun päässä olevat työpuuhun tehdyt muutokset ja lisäykset indeksiin.

  • Indeksiin voidaan myös lisätä nimenomaan tiedostojen poistamisia komennolla git rm.

    • git rm <polku> Poistaa polun tiedostojärjestelmästä sekä lisää poiston indeksiin.

  • Kun kaikki committiin tulevat muutokset on lisätty indeksiin, viimeistellään se komennolla git commit.

    • git commit Luo uuden commitin indeksin pohjalta. Avaa tekstieditorin commit-viestin kirjoittamista varten.

    • git commit -m “<viesti>” Luo uuden commitin indeksin pohjalta. Käyttää annettua viestiä commitin viestinä.

  • Tiedostoja ja versiota voidaan palauttaa komennolla git checkout, jota käytetään myös haarojen vaihtoon.

    • git checkout HEAD – <polku> Palauttaa HEADin version polusta.

    • git checkout <commit> – <polku> Palauttaa polun version commitista ja lisää sen indeksiin.

    • git checkout <commmit> Siirtää HEADin osoittamaan committiin ja päivittää työpuun. Git on tämän jälkeen detached-HEAD -tilassa, josta pitää palata checkouttaamalla johonkin haaraan (tai luomalla uusi haara) ennen kuin committeja voi tehdä.

    • git checkout <haara> Siirtää HEADin osoittamaan haaraan ja päivittää työpuun. Peruskäytössä riittää git checkout main`

  • Paikallisen tietovaraston päivittämiseen suoraviivaisin komento on pull.

    • git pull <etätietovarasto> Jos HEADin haara seuraa jotain etätietovaraston haaraa, git hakee etätietovarastosta commitit, jotka puuttuvat paikallisesta tietovarastosta ja päivittää haaran. Esim. git pull origin

    • git pull <etätietovarsto> <haara> Git hakee etätietovaraston määritellyn haaran ja commitit, sekä yhdistää sen HEADin osoittaman haaran kanssa.

  • Etätietovaraston päivittäminen tapahtuu komennolla git push. Komento siirtää muutokset staging alueelta etätietovarastoon. Pushin avulla saadaan muutokset myös muiden hyödynnettäväksi.

    • git push <etätietovarasto> Puskee HEADin osoittaman haaran etätietovarastoon: git push origin`

    • git push <etätietovarasto> <haara> Puskee haaran etätietovarastoon. Esim. git push origin main`

Demo Gitin käytöstä (kesto 13:40)

Versionhallinta omalla koneella

Kurssilla annetut esimerkit ovat kaikki komentorivillä esitettyjä. Tähän on vahvat perusteet, vaikka erilaisia graafisia vaihtoehtoja Gitin käyttöön on saatavilla. Tällaisia ovat IDEt joko suoraan tai erillisen laajennoksen avulla sekä erilliset graafiset Git-ohjelmistot kuten TortoiseGit ja GitGUI. Tärkein syy sille, miksi kurssi käyttää Gitiä komentoriviltä on, että Git on komentorivityökalu. Konepellin alla kaikki edellämainitut graafiset vaihtoehdot kuitenkin käyttävät samoja komentorivikomentoja. Osaamalla käyttää Gitiä komentoriviltä, ymmärrät parhaiten sen toiminnan periaatteet ja osaat käyttää sitä mistä vaan. Tiivistetysti Gitin opetteleminen komentoriviltä kannattaa, koska se:

  • Auttaa ymmärtämään Gitin toimintaa parhaiten

  • Mahdollistaa Gitiä käyttävien skriptien ja työkalujen tekemisen

  • Mahdollistaa monimutkaisempien ongelmien ratkaisemisen

  • On pakollista monissa IT-alan rooleissa

Ottaaksesi Gitin käyttöön omalla koneellasi tarvitset koneelle tietysti itse Gitin. Sen asentamisen ohjeet eri alustoille on saatavilla Git-kirjassa Pro Git. Kirja on muutoinkin oiva lähde Gitin käyttöön. Windows-koneille suosittelemme Git for Windowsia tai Powershellin asentamista Gitin lisäksi.

Komentorivi

Graafinen käyttöliittymä

- Aloittelijoille vaikea

+ Helpompi vaihtoehto jos komentorivi ei ole tuttu asia

+ Helmpompi ratkoa ongelmia koska internet on täynnä ohjeita komentorivi Gitille

- Vaikea tietää mitä komentoja ohjelma ajaa taustalla

+ Koko dokumentaatio saatavilla suoraan komentoriviltä

+ Tyypillisesti parempi käyttäjäpalaute

+ Rutiinilla kanssa todella nopea

* Osa komennoista nopeampi antaa, osa taas hitaampi

- Historian selaaminen työlästä

+ Historian selaaminen helppoa