2. týždeň

Systémy pre správu verzií

Úvod do systémov pre správu verzií, základy použitia systému Git.

Ciele

  1. Zistiť čo je úlohou systémov pre správu verzií.
  2. Oboznámiť sa so základnými pojmami systému Git.
  3. Naučiť sa základné príkazy pre prácu s Git repozitárom.

Postup

Krok 1: Systémy pre správu verzií

Systém pre správu verzií (skrátene SSV) predstavuje určitý typ „databázy“, ktorá umožňuje zaznamenať stav softvérového projektu vo zvolených časových okamihoch, prezerať históriu týchto záznamov, či vracať sa k predošlým stavom projektu. Takisto umožňuje pracovať na projekte v tíme, keďže do tejto „databázy“ môžu ukladať stav projektu viacerí používatelia, pričom systém poskytuje prostriedky na riešenie konfliktov v prípade zmien rovnakého artefaktu projektu viacerými používateľmi.

Vo všeobecnosti, SSV nie sú obmedzené v tom, v akých typoch súborov môžu sledovať zmeny. Väčšie možnosti, hlavne pre porovnávanie verzií, sú pri textových súboroch, no SSV môže obsahovať ľubovoľné súbory. Z hľadiska vývoja softvéru sú najčastejšie priložené súbory so samotnými zdrojovými kódmi systému a dokumentačné súbory, no prítomné sú aj konfiguračné a zostavovacie skripty, definície závislostí, a ďalšie artefakty.

Význam použitia SSV

Existuje viacero veľmi dobrých dôvodov, prečo používať SSV pri práci na softvérovom projekte:

  • Ukladanie verzií: Ukladanie verzií súborov, ktoré sú súčasťou projektu, je dôležité z hľadiska zálohovania, no má aj iné účely. Ako sa systém vyvíja, je potrebné pridávať nové vlastnosti alebo upravovať existujúce vzhľadom na meniace sa požiadavky používateľov. Z toho hľadiska je dôležitá možnosť vytvorenia viacerých variánt systému, no i možnosť spojiť neskôr takéto varianty do jednej. Systematické ukladanie verzií má aj dokumentačný charakter a okrem toho, že zaznamenáva zmeny projektu v čase, môže napomôcť aj odhaleniu bodu v histórií, kedy bola zavedená určitá chyba, ako aj to, kto ju zaviedol. Aj priebežné revízie kódu často fungujú na báze revidovania rozdielov medzi dvoma zaznamenanými verziami systému.

    SSV zároveň rieši aj „administráciu“ verziovania, keďže konkrétna verzia pozostáva len zo zmien oproti predchádzajúcej verzii (úspora miesta), pričom je vždy zaznamenaný aj čas vytvorenia, správa popisujúca zmeny a autor novej verzie. Významným verziám je možné priradiť aj špeciálne značky.

  • Spolupráca: Spolupracovať na projekte s inými vývojármi len prostredníctvom ustavičného preposielania „balíkov“ s projektom alebo prostredníctvom zdieľaného priečinka nie je z dlhodobého hľadiska akceptovateľné, keďže to rýchlo povedie ku konfliktným zmenám, neprehľadnosti a chybovosti. Ani v prípade ak by viacero vývojárov pracujúcich na projekte malo pridelené rôzne úlohy nie je zabezpečené, že nebudú editované žiadne časti kódu súčasne viacerými z nich. Pri využití SSV, každý vývojár v tíme môže voľne pracovať s ľubovoľnými (textovými) súbormi. Tento systém neskôr umožní spojiť všetky zmeny do spoločnej verzie, ktorá sa stane súčasťou verziovaného systému a bude jednoznačné, že práve táto verzia je aktuálna.

  • Obnovenie predchádzajúcich verzií: Možnosť obnoviť staršie verzie súboru (alebo aj celého projektu) znamená, že aj v prípade vykonania úprav, ktoré sa ukážu ako nevyhovujúce, existuje jednoduchý spôsob, ako sa vrátiť späť.

  • Zistenie zmien: Zakaždým pri vytvorení novej verzie, SSV vyžaduje od používateľa, aby uviedol krátky popis zmien, ktoré vykonal od posledného záznamu verzie. Tieto popisy majú vysokú hodnotu pre ostatných členov tímu, ktorí sa tak dozvedia o uskutočnených zmenách, a vo všeobecnosti dokumentujú vývoj projektu v prirodzenej reči. V prípade, že zmenené súbory sú textové, SSV môže poskytnúť aj vizuálne porovnanie vykonaných zmien v obsahu súboru.

Krok 2: Ako pracuje Git

V rámci predmetu ZSI si prakticky ukážeme použitie SSV na systéme Git. V tomto kroku uvedieme základné princípy, ktorých porozumenie vám pomôže pri práci s týmto systémom. Priebežne uvedieme aj hlavné pojmy (aj ich anglické verzie, s ktorými sa stretnete pri práci so samotným systémom) používané v rámci Gitu.

„Snímky“ projektu

Git spravuje údaje projektu ako vlastný súborový systém. Zakaždým, keď uskutočníte záznam (z angl. commit ) novej verzie, Git vytvorí „snímok“ súborov v danom okamihu a uloží referenciu na tento snímok. Nezmenené súbory pritom neukladá znovu, ale len odkáže na ich poslednú identickú uloženú verziu.

Lokálne operácie

Väčšina operácií v systéme Git si postačí pri svojej činnosti s lokálnymi súbormi bez potreby kontaktovať iné počítače v sieti. Celá história repozitára (z angl. repository ), teda priečinka s projektom pod správou systému Git, je dostupná lokálne. To umožňuje prácu offline pre operácie ako prezeranie histórie, získanie (z angl. checkout ) určitej verzie projektu z repozitára, zaznamenanie (z angl. commit ) novej verzie, a mnohých ďalších. V podstate je systém Git plne použiteľný aj v prípade, ak jediná kópia repozitára je dostupná u vás lokálne.

Samozrejme, systém Git podporuje aj viacero operácií pracujúcich cez sieť, kde sa využije práve jeho decentralizovanosť — viacero úplných kópií repozitára v rámci spolupracujúceho tímu.

Tri stavy

Veľmi dôležité pre prácu so systémom Git je porozumenie trom základným stavom, ktoré tento systém používa pri práci so spravovanými súbormi:

  • Zaznamenané (z angl. commited ) — dáta sú uložené v lokálnej databáze repozitára.
  • Zmenené (z angl. modified ) — súbory sú zmenené, ale ešte neboli zaznamenané do databázy.
  • Pripravené (z angl. staged ) — zmenené súbory, ktoré boli označené v aktuálnom stave pre záznam (commit) do nasledujúcej novej verzie.

To vedie k trom oblastiam projektu pod správou systému Git:

  • .git priečinok — v tomto priečinku (ktorý vznikne pri vytvorení repozitára, alebo pri naklonovaní repozitára z iného počitača) Git ukladá metaúdaje a databázu pre spravovaný projekt.
  • Pracovný priečinok (z angl. working directory ) — obsahuje projekt získaný z konkrétnej zaznamenanej verzie projektu. Súbory v ňom sú načítané z Git databázy, a je možné ich štandardne používať alebo upravovať.
  • Prípravná oblasť (z angl. staging area , niekedy aj index ) — predstavuje súbor v .git priečinku, ktorý obsahuje informácie o tom, čo sa stane novou verziou pri nasledovnom zázname.

Základná práca s Git repozitárom teda vyzerá nasledovne:

  1. Upravíte súbory v pracovnom priečinku.
  2. Pripravíte súbory do prípravnej oblasti vytvorením snímku ich aktuálneho stavu.
  3. Vytvoríte záznam, ktorý vezme súbory z prípravnej oblasti a uloží ich permanentne do .git priečinka (repozitára).
Tri stavy pri lokálnych operáciách
Obr. 1: Tri stavy pri lokálnych operáciách

Krok 3: Konfigurácia Git repozitára

Prejdime k vytvoreniu Git repozitára. Predpokladom je, že v používanom operačnom systéme máte Git nainštalovaný a teda máte k dispozícií program s názvom git. Práve odovzdávaním príkazov tomuto programu budeme pracovať s Git repozitárom v konzole.

Úloha 3.1

Inicializujte nový Git repozitár pre pracovný priečinok test.

Nový repozitár vytvoríme pomocou príkazu init.

 $ git init test

Dôsledkom je vytvorenie priečinka test a v ňom vnoreného priečinka .git. Priečinok test je nami zvolený názov pracovného priečinka a .git priečinok predstavuje novovytvorený repozitár pre tento pracovný priečinok.

Poznámka

Ak chceme ako pracovný priečinok pre nový repozitár použiť ten, v ktorom sa aktuálne nachádzame, použijeme príkaz git init bez špecifikovania názvu pracovného priečinka.

Poznámka

Priečinok .git je automaticky nastavený ako skrytý. Súbory v ňom sú interné súbory Git repozitára, ktoré by sa nemali modifikovať manuálne.

Úloha 3.2

Nastavte informácie o používateľovi.

Ak ste tak ešte nespravili, prejdite do novovytvoreného priečinka test.

 $ cd test

Ako už bolo spomenuté, SSV vyžadujú pri zaznamenávaní nových verzií informácie o autorovi novej verzie. Pri systéme Git je požadované meno a emailová adresa používateľa — autora. Tieto je možné nastaviť buď globálne pre daného používateľa operačného systému, alebo špecificky pre konkrétny repozitár.

Pre globálne nastavenie mena a emailovej adresy pre systém Git použite nasledovné príkazy:

$ git config --global user.name "Janko Hraško"
$ git config --global user.email "janko.hrasko@student.tuke.sk"

Lokálne nastavenie (platné len pre aktuálny repozitár) uskutočníte rovnakými príkazmi, len vynechaním argumentu --global.

Poznámka

Pri zázname novej verzie Git najskôr pozerá na lokálne nastavenie. Ak v ňom nenájde potrebné informácie, pozerá na globálne nastavenie.

Poznámka

Aktuálne nastavenia si môžete overiť zadaním príkazu git config --list

Krok 4: Zaznamenanie verzie

Úloha 4.1

Pripravte súbory v pracovnom priečinku repozitára.

Stiahnite si tento archív s implementáciou hry „piškvorky“ v jazyku C a rozbaľte ho do svojho nového repozitára test.

Úloha 4.2

Skontrolujte stav pracovného priečinka.

Aktuálny stav pracovného priečinka zobrazíte príkazom status :

$ git status

Výstup príkazu by mal vyzerať nasledovne:

On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    README.md
    piskvorky.c
    piskvorky.h

nothing added to commit but untracked files present (use "git add" to track)

Poznámka

Čítajte výpisy Git príkazov. Je to prostriedok, ktorým s vami Git komunikuje, a často sa z nich dozviete nápovedu pre ďalšie akcie, respektíve správu o akejkoľvek neštandardnej situácií.

Vo výpise nás Git informuje, že v pracovnom priečinku sa nachádzajú súbory, o ktorých nemá vo svojej databáze záznam (angl. untracked files ). Zároveň ponúka príkaz, ktorým pripravíme požadované súbory do indexu , resp. prípravnej oblasti — a to príkazom add. Skúsme teda pridať súbor README.md do indexu a vypísať opäť stav pracovného priečinka:

$ git add README.md
$ git status

Tentokrát výpis stavu zobrazuje práve pridaný súbor medzi zmenami pripravenými na záznam ( changes to be commited ). Pre jednoduché pridanie všetkých zmien v aktuálnom priečinku do prípravnej oblasti, môžete spustiť príkaz:

$ git add .

Keď sú už všetky požadované zmeny v pracovnom priečinku pripravené na záznam (môžete to skontrolovať ďalším status príkazom), samotný záznam vykonáte nasledovne:

$ git commit

Po potvrdení príkazu sa otvorí textový editor (napr. vi alebo nano ), v ktorom môžete zapísať správu (angl. commit message ), ktorá sa uloží s vytváraným záznamom. Táto správa by mala popisovať zmeny, ktoré sa udiali. Keďže tento záznam je prvý, môžeme do správy zapísať „prvá verzia“. Akonáhle súbor uložíte a zavriete, záznam bude dokončený, o čom vás Git informuje vo výpise.

Poznámka

V prípade, že chcete zapísať len krátku, jednoriadkovú správu, je možné použiť aj dodatočný argument -m so správou nasledovne:

$ git commit -m "prva verzia"

Krok 5: Prehliadanie histórie

Úloha 5.1

Zobrazte históriu záznamov.

Históriu vytvorených záznamov je možné zobraziť príkazom log, v ktorého výpise uvidíme informáciu o autorovi záznamu, dátum a čas vytvorenia záznamu, ako aj text správy, ktorú sme zaznamenali. Ďalší údaj obsahuje hash odtlačok záznamu, ktoré ho jednoznačne identifikuje.

$ git log
commit c31267f985c96a39ec37d647b4601fca14039c28
Author: Janko Hraško <janko.hrasko@student.tuke.sk>
Date:   Mon Feb 15 09:26:38 2016 +0100

prva verzia

Môžete si všimnúť, že ak teraz použijete príkaz status, git vás informuje o tom, že v pracovnom priečinku nie sú známe žiadne zmeny oproti poslednej zaznamenanej verzii.

Úloha 5.2

Opravte chybu v súboroch v repozitári a zaznamenajte novú verziu.

Ak skúsite skompilovať hru Piškvorky, ktorú máte v repozitári, zistíte, že program obsahuje chybu — použité funkcie sú síce deklarované v hlavičkovom súbore piskvorky.h, no tento súbor nie je vložený do hlavného súboru piskvorky.c. Opravte tento problém vložením nasledovného riadku na začiatok súboru:

#include "piskvorky.h"

Novú verziu zaznamenajte obdobným spôsobom, ako v predošlom kroku. Využite príkazy add a commit, a na overenie status a log. Zvoľte vhodnú záznamovú správu vzhľadom na uskutočnenú zmenu. Po ukončení tejto úlohy by ste mali mať opäť „čistý“ pracovný priečinok.

Úloha 5.3

Zobrazte zmeny medzi poslednými dvoma verziami.

Na zobrazenie zmien je možné použiť príkaz diff. Ak máte v pracovnom priečinku zmenený súbor, jeho zmeny oproti poslednej zaznamenanej verzii môžete zobraziť pomocou tohto príkazu nasledovaným cestou k požadovanému súboru, napríklad:

$ git diff README.md

Zobrazenie zmien medzi dvoma zaznamenanými verziami je možné pomocou ich hash odtlačkov, ktoré môžete zistiť pomocou príkazu log. V prípade, že chceme ale zobraziť zmeny medzi poslednými dvoma zaznamenanými verziami, je možné použiť značky HEAD (posledný záznam v histórií) a HEAD^1 (predposledný záznam), nasledovne:

$ git diff HEAD^1 HEAD

diff --git a/piskvorky.c b/piskvorky.c
index 92daff3..f946295 100644
--- a/piskvorky.c
+++ b/piskvorky.c
@@ -1,6 +1,8 @@
 #include <stdio.h>
 #include <stdlib.h>

+#include "piskvorky.h"
+
 int main() {
     printf("Enter the size of field: ");
     int size;

V tomto prípade vidíme, že v súbore piskvorky.c boli pridané 2 nové riadky, s príslušným obsahom.

Poznámka

Poradie záznamov uvedených v príkaze diff má vplyv na výstup. Zobrazujú sa totiž zmeny vykonané v druhom zázname voči prvému. Ak by ste teda v predošlom príklade prehodili značky HEAD^1 a HEAD , výstup by oznamoval, že došlo k zmazaniu riadku s include.

Poznámka

V niektorých verziách gitu sa zobrazenie zmien medzi poslednými dvoma zaznamenanými verziami vykonáva pomocou príkazu git diff HEAD~1 HEAD.

Krok 6: Rušenie zmien

Úloha 6.1

Zmažte súbor piskvorky.c a zaznamenajte novú verziu

Pre simulovanie situácie neželanej zmeny, zmažte súbor piskvorky.c a pomocou príkazov add a commit zaznamenajte novú verziu.

Poznámka

Pre urýchlenie práce v prípade, ak chcete presunúť do prípravnej oblasti všetky zmeny v aktuálnom pracovnom priečinku a následne vykonať záznam, môžete použiť príkaz commit -am nasledovaný správou záznamu.

Poznámka

V prípade, ak po uskutočnení záznamu zistíte, že ste zabudli presunúť dôležitý súbor do prípravnej oblasti, alebo chcete opraviť preklep v správe záznamu, môžete upraviť predošlý záznam vykonaním príkazu commit s argumentom --amend.

Úloha 6.2

Vráťte sa k predošlej verzii projektu.

Na identifikáciu predchádzajúcich záznamov môžete použiť jednak značku HEAD , alebo hash odtlačky záznamov. Príkazom log zistíte odtlačky. Postačí si skopírovať prvých 8 znakov odtlačku.

Na návrat k predchádzajúcej verzii máme niekoľko možností. Jednou z nich je príkaz revert, ktorý vykoná „opačné operácie“ ako záznam špecifikovaný v jeho argumentoch.

$ git revert HEAD

Git vás požiada o zapísanie správy popisujúcej nový záznam, ktorý ale už bude predvyplnený. Bol teda vytvorený nový záznam, ktorý „otočil“ ten zrušený. História projektu teda ostala neporušená.

Alternatívou je príkaz reset --hard, ktorý vráti históriu projektu do stavu určeného záznamom v jeho argumentoch. Dôležité je upozorniť, že tento príkaz zruší aj všetky nezaznamenané zmeny v pracovnom priečinku alebo prípravnej oblasti. Môžete tento príkaz vyskúšať na návrat do stavu po oprave hlavičkového súboru. Zistite si teda jeho odtlačok (ak ste nasledovali tento návod, je to druhý najstarší záznam) a vykonajte príkaz

$ git reset --hard <odtlacok>

Ak si teraz pozriete log, zistíte, že tam máte len 2 záznamy — prvý a ten s opravou.

Krok 7: Základy práce so vzdialeným repozitárom

Okrem lokálnych operácií Git podporuje aj sieťové, ktoré sú dôležité pre spoluprácu vývojárov pracujúcich na projekte. V tomto kroku si ukážeme základné príkazy na odoslanie záznamov do vzdialeného repozitára.

Úloha 7.1

Vytvorte vzdialený repozitár na školskom Gitlab serveri

Po prihlásení sa na Gitlab server pomocou jedinečného loginu a hesla, budete mať k dispozícií možnosť vytvoriť nový repozitár pod tlačidlom „new project“ v pravej bočnej lište. Pre jeho vytvorenie postačí vyplnenie názvu projektu.

Aby ste sa mohli pripojiť k tomuto vzdialenému repozitáru zo svojho počítača, potrebujete si nastaviť SSH kľúče. Postup pre vygenerovanie kľúčov je opísaný v oficiálnej učebnici Gitu. Vygenerovaný verejný kľúč pridajte do svojho účtu na Gitlabe — kliknite na ikonku používateľa vpravo hore, zvoľte položku „Settings“ a prejdite do časti „SSH Keys“.

Úloha 7.2

Nastavte novovytvorený projekt ako vzdialený repozitár vášho lokálneho repozitára

Gitlab vám po vytvorení projektu poskytne zoznam základných pokynov pre nastavenie repozitára. V našom prípade budeme postupovať podľa pokynov pre už existujúci repozitár „Push an existing Git repository“, a teda v rámci svojho lokálneho repozitára vykonajte príkaz remote add origin, tak ako vám ho zobrazí Gitlab. Pre náš ukážkový príklad to teda bude

$ git remote add origin git@git.kpi.fei.tuke.sk:janko.hrasko/piskvorky.git

Tento príkaz pridá vzdialený repozitár s názvom origin (konvenčné pomenovanie základného umiestnenia repozitára) dostupný na danej adrese.

Úloha 7.3

Odošlite lokálne záznamy do vzdialeného repozitára

Pre odosielanie lokálnych záznamov do vzdialeného repozitára slúži príkaz push. Ak chceme prvýkrát nastaviť, kam sa má projekt odoslať, ak neuvedieme ďalšie argumenty, potrebujeme zavolať príkaz v tvare

$ git push -u origin master

a pri nasledovných odosielaniach stačí použiť príkaz git push. Všetky takéto príkazy odošlú lokálne záznamy do vzdialeného repozitára origin.

Ak si teraz nanovo načítate stránku na Gitlabe, mali by ste tam vidieť váš projekt.

Doplňujúce zdroje

  1. Git Cheat Sheet — krátka prehľad základných príkazov Gitu
  2. Git e-book
  3. Learn Version Control with Git