Receptár Git-u
Spisovateľ práve zasadol za svoj pracovný stôl. Pravou rukou vytiahol zásuvku a z nej zväzok s materiálmi na ktorých v poslednej dobe pracuje. Našiel ich presne v tom stave, v ktorom ich včera zanechal. Okrem práce, ktorú na nich urobil včera, je v nich vidno celú históriu postupného pripisovania, prepisovania, pridávania a škrtania. V tých papieroch je celá história zmien, ktoré doteraz vykonal. Má to jednu výhodu: ak niekedy nadobudne pocit, že pred mesiacom sa jeho práca nachádzala v lepšom stave než dnes, môže sa k stavu spred mesiaca okamžite vrátiť a nadviazať naň.
Programátor práve zasadol za svoj počítač. V editore otvoril zdrojový kód projektu, na ktorom v poslednej dobe pracuje. Našiel ho presne v tom stave, v ktorom ho včera zanechal. Programátor, na rozdiel od svojho kolegu spisovateľa, nevidí v akom stave sa projekt nachádzal pred týždňom alebo pred mesiacom. Programátor je nervózny: ešte predvčerom bol program funkčný ale včera ho začal živelne modifikovať, v dôsledku čoho program znefunkčnil. Navyše, snažiac sa zachrániť čo najviac, začal zmetkovať a v strese zaniesol do kódu ešte ďalšie chyby. Čo by dal programátor za to, keby sa mohol vrátiť k predvčerajšej verzii kódu. Dalo by sa to spraviť, keby si programátor jednotlivé verzie zálohoval. Lenže zálohovanie je pracné a len málo kto je dostatočne disciplinovaný na to, aby zálohoval denne. Náš programátor by to mal na svete oveľa jednoduchšie, keby používal nejaký systém správy verzií. Napríklad git.
Táto stránka je písaná pre tých, ktorí git nikdy nevideli v akcii, ale potrebujú ho používať. Hlboké porozumenie ktorémukoľvek systému správy verzií (zďaleka nie len git-u) vyžaduje uchopenie veľkého množstva abstraktných pojmov. Vďaka tomu začiatočník snažiaci sa preniknúť k podstate trpí. Komenský vraj hovorieval, že učiaci sa človek si najprv osvojí prízemné aspekty veci, a až potom (ak vôbec) je pripravený začať o veci rozmýšlať. Pretože s týmto názorom súhlasím, a pretože git je z môjho hladiska iba nástroj, rozhodol som sa napísať tento tutoriál, ktorý celú problematiku vysvetľuje na niekoľkých jednoduchých receptoch. S takýmto prístupom k vysvetľovaniu vecí polemizuje názor, podľa ktorého je redukcia akéhokoľvek problému na sadu receptov neprípustnou trivializáciou, vhodnou nanajvýš tak pre cvičené opice. Názor je to síce stále menej populárny, je na ňom však veľký kus pravdy. A preto... ak tento receptár čitateľa uráža, je to neklamný znak, že nie je určený pre neho. Jemu odporúčam nazrieť do niektorého spomedzi tisícok iných online textov, ktoré git vysvetľujú na kultivovanej úrovni.
Výber diskutovaných receptov je rýdzo pragmatický. Tento text vnikol primárne pre potreby mojich študentov a to so zreteľom na moju osobnú skúsenosť s tým, ktorá časť git-ovskej rutiny robí začiatočníkovi problémy.
Prvotná dichotómia
Naprieč mojou prezentáciou git-u vedie deliaca čiara, ktorou sú všetky git-ovské úkony rozdelené na miestne a nemiestne. Miestne sú také úkony, na ktoré vám stačí počítač pri ktorom sedíte. Sú to aktivity, ktoré prebiehajú na tom mieste, kde ste aj vy. Na rozdiel od aktivít nemiestnych, ktoré do hry nejakým spôsobom zapájajú vzdialené počítače prístupné pomocou počítačovej siete. Pretože každý človek na tomto svete by si mal ponechať nemiestne prejavy na neskôr, začneme aj my aktivitami miestnymi.
Miestne používanie git-u je dostatočne dobre motivované a ilustrované príkladom z úvodných paragrafov. Je to presne to, čo programátorovi stačí k tomu, aby mal k dispozícii celú históriu zmien projektu, aby mohol viesť dve alebo viac paralelných histórií zmien alebo ich spájať. Už toto predstavuje dosť dobrý dôvod prečo git používať. Lenže tým sa sila git-u zďaleka nevyčerpáva.
Git je obzvlášť silný v kombinácii s možnosťami počítačových sietí. Spolupracujete na projekte s ďalšími programátormi? Gi vám umožní skrotiť zmetok spôsobený skutočnosťou, že viacero programátorov pracuje súčasne na tej istej časti kódu. Git vám umožní pracovať za každých okolností s tou najčersvejšou verziou kódu. Keďže však vaši kolegovia sedia pri vzdialených počítačoch, musíte svoje git-ovské aktivity povýšiť na sieťovú úroveň.
Iný príklad nemiestnej aktivity: na projekte pracuje len jeden programátor, ale programuje zvyčajne pri dvoch počítačoch, doma a v práci. Zakaždým keď odchádza z práce domov, musí aktuálny stav projektu buď nahrať na nejaké sieťové miesto, alebo na prenosný USB kľúč. To preto, aby mohol neskôr stav svojich domácich adresárov synchronizovať so zmenami, ktoré spravil na počítači v práci. Lenže takýto spôsob synchronizácie je krajne nepohodlný - každý kto ho raz skúsil používať na dennej báze velmi dobre vie, koľkokrát stavy pracovných adresárov zabudol zosynchronizovať alebo ich jednoducho nezosynchronizoval z prozaického nedostatku vôle. Git, ak sa používa nemiestne, deleguje celý proces synchronizácie na spustenie jediného jednoduchého príkazu z príkazového riadku.
Predpoklady
Predpokladám, že viete, čo je to príkazový riadok a viete s ním pracovať na elementárnej úrovni. To znamená, že viete z príkazového riadku blúdiť adresárovou štruktúrou filesystému, viete vytvoriť, editovať alebo zmazať súbor alebo, ak pracujete na unixovskej platforme, zmeniť prístupové práva súboru. Môže sa stať, že niektoré príkazy, ktoré sa v tutoriáli objavia nefungujú pod windowsami. Žial, tento tutoriál bude, aspoň zo začiatku, vychádzať z predpokladu, že používate nejaký poriadny operačný systém.
Predpokladám, že stroj, za ktorým použivateľ sedí, má funkčnú inštaláciu git-u. Otázkou ako git nainštalovať a prípadne spojazdniť sa nezaoberám. Zvyčajne s tým nebýva problém. Na väčšine distribúcií linuxu je git automaticky nainštalovaný, a ak náhodou nie, stačí použiť natívny balíčkovací nástroj.
Miestne aktivity
Založenie nového repozitára (init)
Nepríčetný programátor má projekty na ktorých pracuje nahádzané všetky v jednom adresári. Ešte nepríčetnejší programátor ich drží v jednom súbore. Je to vynikajúci nápad - z projektov takto na filesystéme vzniká pôsobivá a chutná bouillabaisse. Nepríčetný programátor už zmysel života našiel a s kľudným svedomím môže v tomto bode prestať čítať. Čokoľvek.
Príčetný programátor má projekty na ktorých pracuje porozdeľované do adresárov. Ešte príčetnejší programátor má aj jednotlivé tieto adresáre ďalej rozdelené na podadresáre. Tieto môžu byť, napríklad, podadresár na všetky zdrojové kódy, špeciálny podadresár na dáta s ktorými program pracuje, alebo podadresár s dokumentáciou. Tu vysvetlíme, čo má príčetný programátor urobiť, aby zabezpečil, že git začne sledovať a pamätať si zmeny a postupný vývin jedného konkrétneho projektu. Ak nie je povedané inak, všetky úkony v tomto tutoriáli spočívajú v spúštaní príkazov z príkazového riadku.
1. V prvom rade treba nastaviť aktuálny pracovný adresár na ten adresár, v ktorom sa nachádza projekt, ktorý chceme git-om sledovať. Ak sa napríklad programátor rozhodne, že chce sledovať projekt v adresári aaa/bbb/ccc, prvý úkon v príkazovom riadku by mal vyzerať takto:
cd aaa/bbb/ccc
2. Teraz nastal ten okamih, kedy treba git-u oznámiť, že zmeny v tomto adresári má sledovať. Docieli sa to takto (všimnite si, že všetky git-ovské úkony spočívajú vo volaní príkazu git):
git init
Práve ste vytvorili git-ovský repozitár. Od tohto okamihu git sleduje všetky zmeny v ktoromkoľvek súbore v tomto adresári alebo jeho lubovoľne hlboko vnorenom podadresári. Ak sa teraz pozriete na obsah aktuálneho adresára, všimnete si, že v ňom pribudol podadresár .git - tu si git drží všetky potrebné informácie o histórii zmien ale aj konfiguračné informácie, ktoré definujú ako sa má git správať v niektorých situáciach.
3A. Ešte pred tým, než začneme git naplno využívať, oplatí sa investovať trošku času do dvoch kozmetických úprav. Prvá spočíva v doladení už vyššie spomenutých konfiguračných informácií. Predpokladajme, že programátor sa volá Jožko Mrkvička a práve sedí za počítačom, ktorému on, Jožko Mrkvička, hovorí zajax. Jožko by mal z ľubovolného podadresára práve založeného repozitára v príkazovom riadku spustiť nasledujúce príkazy:
git config user.name "jozko.mrkvicka@zajax" git config user.email "jozko.mrkvicka@gmail.com"
Prvým príkazom Jožko nastavil používateľské meno a druhým príkazom používateľovu emailovú adresu asociovanú s práve založeným repozitárom. Nie je nijako extrémne dôležité, ako presne ich nastavil. Napríklad konfiguračný parameter user.name, z ktorého názvu by sa mohlo zdať, že má slúžiť na ukladanie používateľovho mena, nastavil na hodnotu "jozko.mrkvicka@zajax", čo nápadne pripomína emailovú adresu, lenže žiadna emailová adresa to nie je. Rovnako dobre mohol použiť aj akýkoľvek iný reťazec. Jožko zvolil tento reťazec preto, aby z neho bolo zrejmé ako sa on, Jožko Mrkvička, volá a súčasne, aby bolo zrejmé aj to ako sa volá počíťač za ktorým práve sedí. Čoskoro sa dozvieme, na čo je to dobré.
Tak isto aj namiesto svojej emailovej adresy mohol Jožko zadať nejakú vymyslenú adresu. Nič hrozné by sa nestalo. Rovnako tak nemusel emailovú adresu nastaviť vôbec, čo, mimochodom, nie je zlý nápad, i keď sú s tým spojené isté sporadické komplikácie, ale tie sa začnú prejavovať až pri nemiestnom používaní gitu a preto ich zatiaľ odložíme ad acta.
Nutné minimum nastavení v čerstvo vytvorenom repozitári predstavuje riadok, ktorým sa nastaví hodnota parametra user.name čo predstavuje iba smiešny zlomok toho, čo sa ponastavovať dá.
3B. Git je dôsledný. Ak mu to nezakážete, bude sa snažiť sledovať zmeny v úplne všetkých súboroch v repozitári. Takéto správanie vie byť v istých situáciach otravné - niekedy vyslovene chcete, aby si niektoré súbory git radšej nevšímal, lebo na ich zmenách vôbec nezáleží. Príkladom takých súborov, ak programujete v jazyku C, sú objektové súbory (tie s koncovkou .o) alebo definitívny výsledok prekladu (výsledný spustiteľný súbor). Tieto súbory sledovať netreba, pretože ak máte k dispozícii zdrojové kódy, stačí ich skompilovať a máte aj vyššie spomenuté.
Sledovanie súborov možno gitu zakázať pomocou konfiguračného súboru .gitignore. Tento súbor vytvoríme v hierarchicky najvyššom adresári repozitára, hneď vedľa adresára .git, ktorému sme sa venovali v predchádzajúcom paragrafe. V našom prípade je ním adresár aaa/bbb/ccc. Ukážkový súbor .gitignore by mohol vyzerať napríklad takto:
*.o bin/hello data/
Prvým riadkom gitu zakážeme aby svoju pozornosť venoval súborom s príponou "o" a to v celom repozitári, či už sa nachádzajú v hierarchicky najvyššom adresári, alebo v nejakom jeho podadresári. Druhým riadkom gitu zakazujeme, aby sledoval súbor "hello" v podadresári "bin". Treetím riadkom gitu zakazujeme sledovať všetko, čo sa nachádza v podadresári "data". Je jasné, že .gitignore nemusí vyzerať presne takto. Treba ho prispôsobiť konrkétym potrebám, čo väčšinou znamená potrebu nazrieť do detailnej dokumentácie.
Zistenie stavu repozitára (status)
Git je pracovitý - dôsledne sleduje zmeny vo všetkých súboroch v repozitári (ak nie je povedané inak) a tieto zmeny vidí. Súčasne je však slušne vychovaný - sám od seba nás vlastnými múdrymi pozorovaniami nebude otravovať. Ak si niečo všimne, nechá si to pre seba. Dobre, lenže z času na čas predsa potrebujeme vedieť, čo si git všimol. Ak by sme sa to nemali ako dozvedieť, nebolo by to celé na nič dobré. Pretože git nerozpráva sám od seba, ak sa chceme niečo dozvedieť, musíme sa na to opýtať. Robí sa to pomocou gitovského príkazu status takto:
git status
Ak sme práve vytvorili čerstvý repozitár podľa receptu v predchádzajúcom paragrafe, git by mal odpovedať takto:
On branch master No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore nothing added to commit but untracked files present (use "git add" to track)
Týmto nám git hovorí vela rôznych vecí, väčšinu z nich odignorujeme a vrátime sa k nim neskôr. Na tomto mieste sa pristavíme pri hláške: "Untracked files" ktorou nám git oznamuje, že v adresári vidí súbor .hgignore a že tento súbor aktuálne nie je sledovaný. Všetky súbory, ktoré sa nachádzajú v repozitári možno rozdeliť do nasledujúcih piatich skupín:
- Súbory, ktorých stav nebol ešte ani raz zapamätaný -- budeme im hovoriť nesledované súbory, tie sa ďalej delia na
Ignorované nesledované súbory (tomuto stavu budeme hovoriť I na počesť slova Ignore)
Neignorované nesledované súbory (tomuto stavu budeme hovoriť U na počesť slova Untracked)
- Súbory, ktorých stav už raz zapamätaný bol -- budeme im hovoriť sledované súbory, tie sa ďalej delia na
Sledované súbory, ktorých aktuálny stav nie je zapamätaný (tomuto stavu budeme hovoriť M na počesť slova Modified)
Sledované súbory, ktorých aktuálny stav je zapamätaný (tomuto stavu budeme hovoriť C na počesť slova Committed)
Súbory, ktoré sú pripravené na najlbižšie zapamätanie stavu (tomuta stavu budeme hovoriť S na počesť slova Staged)
To, že git považuje súbor ".gitignore" za "Untracked" nám hovorí, že súbor je v stave U. Ak by bol súbor v stave I, git by nám o ňom nehovoril vôbec nič.
Jožko Mrkvička už má hrania sa s gitom pre túto chvíľu dosť a začína sa venovať programovaniu. V adresári projektu vytvára podadresáre src a bin, prvý zdrojový kód ./src/hello.c a jeho kompiláciou vytvára objektový súbor ./src/hello.o a spustitelný súbor ./bin/hello. Ak teraz spustíme git status mali by sme uvidieť niečo takéto:
On branch master No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore src/ nothing added to commit but untracked files present (use "git add" to track)
Git nám tým hovorí, že v repozitári je jeden súbor v stave U (je to súbor .gitignore) a ďalej, že je tu jeden adresár, v ktorom sú ďalšie súbory v stave U (je to adresár src). Všimnime si, že o adresári bin, ktorý tiež v repozitári pribudol v dôsledku programovania, git nič nehovorí. Je to preto, lebo všetko čo sa v tomto adresári nachádza je v ignorovanom stave I. Ale buďme presní, v adresári bin sa aktuálne nachádza súbor hello lenže jeho sledovanie je v súbore .gitignore zakázané a to je dôvod, prečo sa nachádza v ignorovanom stave I. Vidíte, pribudlo viac súborov, git sa však stará iba o tie z nich, ktoré nemá prikázané ignorovať z titulu .gitignore.
Príprava súboru na zapamätanie (add)
V tomto momente git vidí viacero súborov v stave U o ktorých nevie, či ich zmeny sledovať má alebo nie a pýta sa nás na ne. Povedzme, že Jožko Mrkvička chce začať sledovať súbor src/hello.c. Docieli to tým, že gitu aspoň raz prikáže prikáže, aby si zapamätal jeho stav. Lenže aby si git stav nejakého súboru zapamätal, musí si najprv súbor na zapamätanie pripraviť. Príprava spočíva v tom, že sa súbor uvedie do stavu S. Súbor možno do stavu S priviesť jednak zo stavu U alebo zo stavu M, v oboch prípadoch s použitím gitovského príkazu add takto:
git add ./src/hello.c
Ak teraz spustí príkaz git status uvidí toto:
Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: src/hello.c Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: .gitignore
Git nám týmto oznamuje viacero vecí. Jednak si všimol, že súbor ./src/hello.c je pripravený na zapamätanie, čiže, že je v stave S. Pozná sa to podľa toho, že je uvedený v sekcii "Changes to be committed" aj spolu s návodom, ako ho zo stavu S dostať naspať do prechádzajúceho stavu, ak by sme si to chceli so zapamätávaním súboru rozmyslieť. Súbor .gitignore je stále v stave U, ale git nás tentokrát upozorňuje na niečo iné. Niektoré súbory sú pripravené na najbližšie zapamätanie stavu a niektoré nie sú. Súbor .gitignore je jeden z tých ktoré nie sú. Na toto nás git teraz upozorňuje, to že je súbor .gitignore v stave U teraz gitu nepripadá natoľko dôležité, aby nás o tom informoval. Najbližšie nás o tom začne informovať v momente, keď žiadne iné súbory nebudú v stave S.
Zapamätanie stavu repozitára (commit)
Git už sleduje obsah repozitára a všíma si zmeny v niektorých jeho súboroch. To, že si zmeny všíma však neznamená, že si tieto zmeny aj pamätá. Ak chceme, aby si niektorý stav repozitára zapamätal, musíme mu to prikázať. V predchádzajúcom odseku sme videli, ako Jožko Mrkvička pripravil prvý súbor na zapamätanie stavu. On, Jožko Mrkvička, by teraz chcel, aby si git zapamätal stav, v ktorom sa čerstvo pridaný súbor nechádza. Urobí to takto:
git commit -m "prvotny stav repozitara"
Zapamätaniu stavu repozitára sa hovorí "commit" a slúži naň príkaz git commit.Všimnite si, že príkaz má parameter -m za ktorým nasleduje reťazec. Tento by mal byť nejakým viacmenej stručným ale určite výstižným popisom, z ktorého je jasné, čím je zapamätaný stav význačný. Alebo čím sa líši od prechádzajúceho zapamätaného stavu. Jožko Mrkvička si práve zapamätáva stav čerstvo vytvoreného repozitáru, je to úplne prvý zapamätaný stav v poradí, žiadny predchádzajúci zapamätaný stav neexistuje a preto sa rozhodol pomenovať ho "prvotny stav". Git by mal na spustenie tohto príkazu reagovať takto:
[master (root-commit) dca39c1] prvotny stav repozitara 1 file changed, 8 insertions(+) create mode 100644 src/hello.c
Git nám týmto oznamuje, že úspešne do histórie zmien repozitára úspešne uložil aktuálny stav tých súborov, ktoré boli pripravené na zapamätanie. Ďalej nám oznamuje, že aktuálna vetva repozitáru je vetva master -- čo presne to znamená si možno vysvetlíme neskôr, na tomto mieste to nie je dôležité. Hláškou (root-commit) nám oznamuje, že sme práve vykonali prvé zapamätanie stavu tohto repozitára. Túto hlášku už viac neuvidíme. Záhadný reťazec ktorý nasleduje je fragment (temer) jedinečného čísla, ktorým bude predtavovať meno komitu, ktorý sme práve vykonali. Riadok je uzavretý znením popisného textu, ktorým je komit vysvetlený. Na nasledujúcom riadku sa dozvedáme, že v rámci komitu bol zapamätaný stav jedného súboru a že oproti predchádzajúcemu zapamätanému stavu (ktorý neexistuje) pribudlo v tomto súbore 8 riadkov. To teda znamená, že zdrojový kôd, ktorý Jožko naprogramoval má presne 8 riadkov. Správa je uzavretá ďaľšou technickou hláškou, ktorej sa nebudeme venovať.
Ak sa teraz gitu opýtame na stav repozitára (pomocou git status), mali by sme dostať takúto odpoveď:
On branch master Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore nothing added to commit but untracked files present (use "git add" to track)
Týmto nám git oznamuje, že v adresári repozitára sa nachádza jeden súbor, ktorého stav nebol ešte ani raz zapamätaný a nie je ignorovaný. Ide o súbor .gitignore a git nás velmi silno nabáda, aby sme ho začali sledovať. Doslova nám radí, ako to máme spraviť. Git je z tejto situácie trochu nervózny -- najradšej by sledoval všetky súbory v repozitári a tejto ambície sa vzdáva iba vtedy, keď mu explicitne povieme, že si to v prípade niektorého súboru neželáme. Súbor .gitignore sme mu ignorovať neprikázali no a tak ho neignoruje. A vidí, že stav tohto súboru zatiaľ ešte nebol ani raz zapamätaný.
V tomto okamžiku sa Jožko môže venovať programovaniu. Povedzme, že v súbore hello.c vykonal niekoľko drobných zmien. Ak sa teraz gitu opyta na stav repozitara, dozvie sa toto
On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: src/hello.c Untracked files: (use "git add <file>..." to include in what will be committed) .gitignore no changes added to commit (use "git add" and/or "git commit -a")
Git mu dáva na vedomie, že v repozitári sa nachádzajú dva problematické súbory. Prečo je problematický súbor .hgignore už vieme - git sa stále trápi tým, že stav tohto súboru nebol nikdy zapamätaný, a chcel by ho sledovať. So súborom hello.c má git iný problém - to, že ho má sledovať vie. Všimol si však, že tento súbor sa aktuálne líši od stavu, v ktorom bol naposledy zapamätaný a dáva nám na výber z dvoch možností ako s touto situáciou naložiť. Jednak nám hovorí, ako máme postupovať, ak chceme do repozitáru uložiť nový, zatiaľ nezapamätaný stav súboru. Ale dáva nám ešte aj druhú možnosť -- pripúšťa, že zmeny v súbore hello.c sme urobili omylom, a že sa chceme vrátiť k jeho pôvodnému stavu a oznamuje nám, že to sa dá pomocou príkazu git checkout. Povedzme, že Jožko Mrkvička si je zmenami v súbore, ktoré vykonal istý a chce ich zapamätať. Vykoná preto nasledujúce príkazy:
git add ./src/hello.c git commit -m "vylepsenie programu hello, drobna zmena vo vypise retazca hello world"
No a povedzme, že Jožka už nebaví počúvať git ako sa sťažuje, že v repozitári je nesledovaný súbor a tak začne sledovať aj ten:
git add .gitignore git commit -m "do repozitara pridane .gitignore"
Ak sa gitu opýtame na stav repozitára teraz, dozvieme sa toto:
On branch master nothing to commit, working tree clean
Git tým oznamuje, že v repozitári je všetko v stave, s ktorým nemá problém. Konkrétne to znamená, že aktuálna podoba súborov je zapamätaná a že v repozitári sa nenachádza žiaden neignorovaný nesledovaný súbor. Git je spokojný, tu aktuálne nie je čo robiť. Predstavme si, že je spokojný aj Jožko Mrkvička a po dni plnom programovania sa ide poriadne vyspať. Keď na druhý deň ráno vstane a chce pokračovať v programovaní, v repozitári nájde nie len aktuálne podoby zapametaných súborov, ale aj historiu ich zmien.
Zobrazenie histórie repozitára (log)
Deň dva. Jožko Mrkvička si opäť sadá k počítaču. Bude programovať. Pred tým však rád by si pripomenul, na čom pracoval včera. Git mu vie pomôcť. Existuje príkaz, ktorý zobrazí históriu všetkých doposial vykonaných commitov na repozitári. Vyzerá to takto:
git --no-pager log
Ak sa história repozitára vyvíjala tak, ako to popisuje tento tutoriál, výstup by mal vyzerať takto:
commit 478beebe94fc76adca1961447ec16d107f0d5ea7 Author: jozko.mrkvicka@zajax <jozko.mrkvicka@gmail.com> Date: Thu Feb 14 02:43:16 2019 -0900 do repozitara pridane .gitignore commit 267a0cd0ac29b5572b7ba0f0bd9095d785726a7c Author: jozko.mrkvicka@zajax <jozko,mrkvicka@gmail.com> Date: Thu Feb 14 02:42:56 2019 -0900 drobna zmena programu hello, vylepsenie vo vypise retazca hello world commit dcf98f3f6a67e30749f328f2737b6aa9726c90cc Author: jozko.mrkvicka@zajax <jozko.mrkvicka@gmail.com> Date: Thu Feb 14 02:09:52 2019 -0900 prvotny stav repozitara
Git nám oznamuje, že stav repozitára bol zapamätaný zatiaľ trikrát. Vo všetkých prípadoch to bol Jožko Mrkvička sediaci za počítačom zajax kto stav repozitáru uložil. Ďalej vidíme, kedy ku commitom došlo, a pri každom komite vidíme aj krátky popisný reťazec, ktorým sme vysvetlili o čo v danom commite išlo. Navyše je každý komit uvedený svojim pomerne dosť neintuitívnym menom.
Tým, ktorí nemajú radi príkazový riadok dávam do pozornosti grafické rozhrania, ktoré znázorňujú históriu repozitára v prehladnej grafickej podobe. Jedným takým prehliadačov je linuxovská aplikácia gitk, ak ju spustíte z adresára, ktorý patrí gitovskému repozitáru, okamžite Vám zobrazí historiu jednotlivých komitov v prehladnej grafickej podobe.
Úmyselné rozvetvenie histórie (branch)
Úmyselné zvetvenie histórie (merge)
Zhrnutie miestnej agendy
Nemiestne aktivity
Založenie vzdialeného repozitára na bitbuckete
Bitbucket je internetová služba, ktorá umožnuje udržovať na internetovom (a teda viacmenej odvšadial prístupnom) mieste vaše GIT-ovské repozitáre. Nie je to zďaleka jediná takáto služba a, s výnimkou tejto sekcie (o zakladaní nového úložiska), sú rady tohto tutoriálu prenesiteľné na ktorúkoľvek z nich.
Ak chcete bitbucket používať, musíte si tam, samozrejme, najprv vytvoriť konto. Ideálne spriahnuté s nejakým mailboxom, ktorý reálne použivate - bitbucket umožňuje emailové zasielanie informácií o zmenách v repozitároch. Ak už konto máte a ste pod svojou identitou na bitbucket prihlásení, môžete na ňom založiť (alebo zrušiť) vzdialený git-ovský repozitár.
Tu predpokladám, že na miestnom počítači už máte nejaký repozitár, ktorý chcete začať používať nemiestne. Na bitbuckete najprv v ľavostrannej navigácii kliknite na symbol "+" (veľký znak plus). Tým sa celá ľavostranná navigácia prekryje novým menu "Create". V ňom klinite na možnosť "Repository". Bitbucket sa následne pýta na
- meno projektu (zvoľte si nejaký relevantný názov)
- či má byť repozitár privátny (pre začiatok zvoľte áno, použivateľov s právom prístupu pridáte neskôr)
- či má byť zahrnutý aj readme file (nepodstatné, ak neviete, dajte nie)
- či má byť repozitár git-ovský alebo mercurial-ovský (podstatné, zvoľte git)
A v rámci pokročilých nastavení
- stručný popis projektu (kým programujete pre mňa, netreba)
- forking (pokiaľ programujete pre mna nechajte "Allow only private forks"
- issue tracking (dobrá črta, dajte áno)
- wiki (pokiaľ programujete iba pre mna, wikinu netreba)
- predominantný jazyk projektu (pokiaľ programujete pre mňa, zvoľte C bez dekorácií)
Po odoslaní týchto informácií objaví sa vám hlavná stránka čerstvo založeného repozitára. Pretože ste doň zatial neposlali žiadne reálne dáta, zobrazuje sa tam akýsi help s niekoľkými jednoduchými receptami. Pre nás je podstatná iná informácia: hneď po tučným nápisom "Let's put some bits in your bucket" sa nachádza combo-box z ktorého možno vybrať buď "SSH" alebo "HTTPS". Pokiaľ pracujete na mojich zadaniach, vyberte "HTTPS". Vo vedľajšom input boxe sa objaví reťazec "git clone XYZ" pričom časť XYZ ma štruktúru
https://LOGIN@bitbucket.org/LOGIN/REPO
kde LOGIN je meno vašej bitbucketoveskej identity a REPO je meno čerstvo založeného bitbucketovského repozitára. Je to vlastne url, cez ktoré možno ku vzdialenému repozitáru pristupovať a preto mu budeme (celému, vratane prefixu https://) v ďaľšom texte hovoriť budeme hovoriť ADRESA_REPOZITARA.
Spriahnutie vzdialeného repozitára s miestnym repozitárom
Podľa receptu v predchádzajúcej sekcii ste si vytvorili vzdialený repozitár. Zatiaľ však nie je jasné, z čoho vyplýva, že je to vzdialená verzia jedného konkrétneho miestneho repozitára, ktorý máte na lokálnom počítači. Váš lokálny repozitár nemá skade vedieť, že ste práve na bitbuckete vytvorili akési sieťová úložisko. Tu si vysvetlíme ako to miestnemu repozitáru oznámiť.
V príkazovom riadku na miestnom počítači pomocou príkazu cd nastavte aktuálny adresár na adresár toho miestneho repozitáru, ktorý chcete spárovať s repozitárom na bitbuckete. Následne v príkazovom riadku spustite príkaz
git remote add origin ADRESA_REPOZITARA
kde ADRESA_REPOZITARA je reťacez vysvetlený vyššie. Týmto ste svojmu miestnemu repozitáru vysvetlili, že na internete sa nachádza vzdialený repozitár na ktorom sa budú, zakaždým keď o to požiadate, zrkadliť jeho zmeny.
Zreteľne ide o príkaz gitu. Podpríkaz remote špecifikuje, že pracujete so vzdialenými repozitármi aktuálneho miestneho repozitára. Napokon popodpríkaz add znamená, že pridávate informáciu o novom vzdialenom repozitári. Ďalej oznamujete, že tomuto vzdialenému repozitáru budete v rámci ktuálneho miestneho repozitára hovoriť "origin". Je veľmi praktické mať pre rôzne vzdialené repozitáre takéto symbolické mená, pretože ADRESA_REPOZITARA býva niekedy veľmi komplikovaným a dlhým reťazcom. Nepokon repozitáru oznamujete, kde na internete sa vzdialený repozitár nachádza. Po vykonaní tohto príkazu bude Váš miestny repozitár vedieť, že má vzdialenú verziu a kedykoľvek ho o to správnym spôsobom požiadate, bude sa s ňou synhronizovať.
S jedným vzdialeným repozitárom možno spriahnuť viacero miestnych repozitárov. Ak napríklad na jednom projekte pracujete na viacerých počitačoch, spriahnite s bitbucketovským repozitárom miestne repozitáre tohoto projektu na kaďom jednom počitači kde sa tento nachádza. Ak na jednom projekte pracuje viacero programátorov, každý z nich môže spriahnuť svoj miestny repozitár s dohotnutým spoločným repozitárom na bitbuckete (i keď toto nie je preferovaný spôsob zdielania zmien).
Prenos komitov z lokálneho repozitára na vzdialený (push)
Zrkadlenie zmien miestneho repozitára na spárovanom bitbucketovskom repozitári sa nedeje automaticky. Ak vykonáte na miestnom repozitári commit (alebo viac commitov), tento sa neprejaví na jeho bitbucketovskom zrkadle. Ak chcete, aby sa tieto zmeny preniesli aj na bitbucket, musíte to gitu prikázať. Takto:
git push origin master
Venujme sa chvíľu štruktúre tohto príkazu. Lokálne komity sa na vzdialený repozitár prenesú v dôsledku toho, že gitu prikážeme, aby vykonal takzvaný push. Príkaz push má dva parametre, prvým je meno vzdialeného repozitára na ktorý sa majú lokálne komity preniesť. Ak je náš repozitár zosynchronizovaný iba s jedným vzdialeným repozitárom, ktorého meno je origin niet o čom rozmýšlať -- zmeny budeme prenášať na repozitár origin. Ak by mal repozitár viacero vzdialených náprotivkov, mohli by sme si vybrať, na ktorý z nich budeme lokálne komity prenášať. A bol by to práve tento parameter príkazu git push ktorým by sme gitu oznámili o ktorý vzdialený repozitár nám ide. Druhým parametrom príkazu je informácia o tom, z ktorej vetvy miestneho repozitára chceme preniesť komity na vzdialený repozitár -- ak má náš repozitár iba jednu vetvu master opäť niet o čom rozmýšlať. Uvedieme tu máster a hotovo.
Git neprenáša celú históriu zmien repozitáru. Prenášajú sa iba tie commity, ktorými sa miestna verzia histórie líši od histórie na bitubuckete. Ak sa teraz pozriete na bitbucketovskú stránku svojho repozitára a kliknete kartu "commits" uvidíte tam históriu jednotlivých commitov. Na vrchu tejto histórie by sa mali nachádzať čerstvo prenesené commity.
Môže sa stať, že tento proces sa skončí nezdarom (git v takom prípade frfle). Toto sa stáva ak časť vašej miestnej histórie nie je na bitbuckete a súčasne časť bitbucketovskej histórie nie je u vás. Úplne štandardne k tomu dochádza, ak má k jednému bitbucketovskému repozitáru prístup väčšie množstvo ľudí (kým programujete v miestnom repozitári, váš kolega pushuje na bitbucket svoje zmeny). V takej situácii treba takzvane vyriešiť konflikt. Tento tutoriál o riešení konfliktov zatiaľ nepojednáva.
Prenos komitov zo vzdialeného repozitára na lokálny (pull)
Možnosť prenášania zmien z miestnych repozitárov na bitbucket by nebola na nič, keby sa zmeny nedali prenášať aj opačným smerom, z bitbucketu do miestneho repozitára. Je samozrejmé, že sa to dá - z adresára repozitáru stačí spustiť tento príkaz:
git pull [vzdialený repozitár] [vetva]
V prípade, ak je s repozitárom spriahnutý iba jeden vzdialený repozitár origin a vo oboch repozitároch je iba jedna vetva master, príkaz bude vyzerať takto
git pull origin master
Je možné, že git si od vás vyžiada heslo (mohlo by byť nebezpečné keby si stav vášho repozitára mohol stiahnuť ktokoľvek) a po jeho úspešnom zadaní sa jednotlivé commity prenášajú po šifrovanej linke do miestneho repozitára. Git tento proces komentuje. Popritom sa stav aktuálneho repozitáru automaticky mení na úroveň najčerstvejšieho preneseného komitu.
V prípade, že stav miestneho repozitára medzičasom divergoval od stavu bitbucketovského repozitára, príkaz nezbehne úplne a git vás vyzve, aby ste vyriešili konflikty.
Vytvorenie miestnej kópie vzdialeného repozitára (clone)
Programujete, v miestnom repozitári si zapamätávate zmeny a tieto zmeny pushujete na bitbucket. Zatial sú v hre dva repozitáre - jeden miestny a jeden na bitbuckete. Čo ak chcete na projekte začať pracovať pri dvoch rôznych počítačoch? Hodilo by sa, keby ste vedeli kompletne celú históriu projektu stiahnuť z bitbucketu na počítač, na ktorom nikdy žiadny miestny repozitár s projektom nebol. Robí sa to pomocou príkazu:
git clone ADRESA_REPOZITARA
kde reťazec ADRESA_REPOZITARA je bitbucketovská adresa, ktorú sme diskutovali už vyššie. Po zbehnutí tohto príkazu vám na disku pripudbe nový adresár a v ňom presná kópia stavu, ktorý je uložený na bitbuckete, vrátane celej histórie jeho zmien. Až na jeden detail - tento repozitár nemá nakonfigurované meno a adresu majiteľa. Treba ju nakonfigurovať podobne ako sme to spravili v bode 3A sekcie o založení nového repozitára. Upozornenie: je vhodné nastaviť na novej kópii repozitáru tieto parametre INAK než ako sú nastavené v pôvodnom repozitári. Vďaka tomu budeme pri pohľade na log (čiže históriu komitov) repozitára vidieť nielen to, kedy aký komit vznikol, ale budeme vedieť rozlíšiť aj, pri ktorom počítači vznikol. Hádam netreba vysvelovať, prečo môže byť pohodlné mať takúto informáciu k dispozícii.