Git

Ať už programuješ nebo píšeš dokumenty, stává se, že vytvoříš několik verzí. Tuhle chceš archivovat část, která už není potřeba, tamhle chceš svoji práci poslat k ohodnocení, nebo dokonce kolegům, kteří na ni spolupracují. A když se verze začnou kupit, může být problém se v nich vyznat.

Část těchto problémů řeší nástroje jako Dropbox či Google Drive, se kterými ses možná již setkal/a. Tam můžeš například sdílet svůj dokument s dalšími lidmi nebo se můžeš vrátit k dřívější verzi dokumentu, když něco pokazíš a nemůžeš si vzpomenout, jak to bylo předtím. Příklad toho, jak to může vypadat, je zde:

Verzovací Rozhraní služby Dropbox

V tomto rozhraní ale vidíš pouze verze jednoho dokumentu a navíc nemůžeš tušit, ke které verzi se to vlastně chceš vrátit. Nevidíš ani čím se jednotlivé verze liší. Pro větší projekt by byl takový způsob práce neefektivní.

Programátoři proto používají mocnější nástroje na správu verzí (angl. version control system. VCS). Asi nejpopulárnější z nich je Git, se kterým se teď seznámíme.

Budeme hodně pracovat s příkazovou řádkou. Jestli se s ní ještě nekamarádíš, koukni se na úvod.

Nezapomeň: $ na začátku se nepíše; je tu proto, aby šlo poznat že jde o příkaz.

Instalace

Popis instalace Gitu najdeš zde. Jestli jsi instalaci přeskočil/a, projdi si ji teď.

Repozitář

Každý projekt, který budeš verzovat, musí mít pro sebe vyhrazený adresář. Vytvoř si tedy nový adresář a přepni se do něj (pomocí cd). Pak vytvoř gitový repozitář (angl. repository) pomocí příkazu git init:

$ git init
Initialized empty Git repository in ./.git/

Na první pohled to vypadá, že se nic nestalo. Tenhle příkaz totiž vytvořil skrytý adresář .git, do kterého uložil nějaké informace. Přesvědč se příkazem ls -a (Linux) nebo dir /a (Windows). Adresář .git je schovaný proto, že ho spravuje Git a ty bys v něm neměl/a nic měnit.

V repozitáři zatím nic není. Zkus to ověřit příkazem git status, který vypisuje informace o stavu repozitáře:

$ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

„On branch master” říká něco o větvích, k tomu se vrátíme později. „Initial commit” říká, že zatím nemáš uloženou žádnou revizi. A „nothing to commit” říká, že je adresář prázdný – nejsou tu žádné soubory k verzování.

První revize

Teď si zkus do Gitu něco přidat!

Vytvoř soubor basnicka.txt a napiš do něj nějakou básničku. Měla by mít aspoň pět řádků, ať pak máme s čím pracovat. Pak zkus znovu git status: Git oznámí, že v adresáři je soubor, o kterém ještě „neví“.

$ git status
On branch master

Initial commit

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

        basnicka.txt

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

U každého nového souboru musíme Gitu říct, že chceme jeho obsah sledovat. Proveď to se svojí básničkou:

$ git add basnicka.txt

a znovu zkontroluj stav repozitáře:

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   basnicka.txt

To, co je zelené („changes to be committed“), se přidá do další revize (angl. commit), kterou vytvoříš. Pojď tedy vytvořit revizi:

$ git commit
[master (root-commit) 1a009f4] První revize
 1 file changed, 6 insertions(+)
 create mode 100644 basnicka.txt

Po zadání tohoto příkazu se otevře editor, do kterého musíš napsat nějaký popisek, abys věděl/a, co tahle revize obsahuje za změny. Pro začátek napiš jen První revize. Předvyplněné řádky začínající # nech být (nebo vymaž, podle chuti – Git je ignoruje). Pak soubor ulož a zavři editor.

Jak na editory?

Na Windows, máš-li správně nastavený Git, se použije Poznámkový blok (Notepad) – stačí něco napsat, uložit (Ctrl+S) a zavřít (Alt+F4).

Na Linuxu a macOS se objeví editor v příkazové řádce, který se jmenuje Nano. Pozná se tak, že v dolních dvou řádcích má malou nápovědu. Něco napiš, pomocí Ctrl+O soubor ulož, potvrď jméno souboru (Enter) a pomocí Ctrl+X editor zavři.

Nemáš-li Git nastavený podle instrukcí, objeví se přímo v příkazové řádce Vim – poměrně složitý editor, který se teď učit nebudeme. Pozná se tak, že úplně spodní řádek je prázdný. V takovém případě stiskni Esc, napiš :q! (dvojtečka, Q, vykřičník) a potvrď pomocí Enter. Pak si nastav Git a zkus git commit znovu.

Znovu zkus vypsat stav repozitáře:

$ git status
On branch master
nothing to commit, working tree clean

Tenhle krátký výstup znamená, že od poslední revize se nic nezměnilo. Což dává smysl – poslední revizi jsi právě vytvořil/a!

A co všechno je v téhle první/poslední revizi? To ti poví příkaz git show:

$ git show
commit 1a009f4267d5a6ab7ece87cb7514f5b803692e39
Author: Adéla Novotná <adela.novotna@example.cz>
Date:   Mon Mar 20 14:51:34 2017 +0100

    První revize

diff --git a/basnicka.txt b/basnicka.txt
new file mode 100644
index 0000000..558d133
--- /dev/null
+++ b/basnicka.txt
@@ -0,0 +1,6 @@
+Holka modrooká, nesedávej u potoka
+Holka modrooká, nesedávej tam
+
+V potoce je hastrmánek
+Zatahá tě za copánek
+Holka modrooká, nesedávej tam

Vidíš unikátní označení revize, pomocí kterého se vždy bude dát dostat k této konkrétní verzi projektu. Pak je tam jméno autora a datum vytvoření, popisek a nakonec shrnutí změn: byl přidán soubor basnicka.txt s nějakým obsahem.

Když je výpis moc dlouhý, můžeš se v něm pohybovat (, , PgUp, PgDn) a zpět se dostaneš klávesou Q jako Quit.

Kódování ve Windows

Pokud výpis nezvládá znaky s diakritikou, zadej před git show příkaz

> set LC_ALL=C.UTF-8

Tento příkaz nastaví aktuální terminál: když si ovevřeš nové okno s příkazovou řádkou, bude ho potřeba zadat znovu.

Druhá revize

Udělej v básničce nějakou malou změnu – změň slovo, uprav interpunkci nebo přidej sloku. Pak se opět zeptej Gitu na stav repozitáře.

$ git status
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:   basnicka.txt

no changes added to commit (use "git add" and/or "git commit -a")

Soubor je opět červený! Něco se v něm změnilo! Ale co? Na to nám odpoví příkaz git diff.

$ git diff
diff --git a/basnicka.txt b/basnicka.txt
index 558d133..24e2384 100644
--- a/basnicka.txt
+++ b/basnicka.txt
@@ -1,6 +1,9 @@
-Holka modrooká, nesedávej u potoka
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej u potoka
+Holka modrooká
+Nesedávej tam
 
 V potoce je hastrmánek
 Zatahá tě za copánek
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej tam

Změny se ukazují po řádcích. Červeně, s -, jsou ukázány odebrané řádky; zeleně s + řádky přidané.

Změnilo-li se na řádku jen jedno slovo nebo i písmeno, celý řádek se ukáže jako smazaný a zase přidaný. Dá se to nastavit i jinak, když je potřeba, ale je dobré si na tento standard zvyknout.

Takhle se dá jednoduše zjistit, co se dělo od poslední verze. Když ti program přestane fungovat (a v poslední uložené revizi fungoval), použij git diff – v jedné ze změn musí být chyba!

Řádek začínající @@ říká, kde v souboru změna je (u mě začínal vypsaný kousek souboru řádkem 1 a měl 6 řádků; v nové verzi je opět od 1. řádku, ale narostl na 9).

Jsi-li se změnami spokojen/a, řekni Gitu, ať je použije v další revizi:

$ git add basnicka.txt

A pro úplnost se znovu koukni, co říká status – co je zelené, přidá se do další revize.

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   basnicka.txt

Než uděláš druhou revizi, ještě řeknu něco o tom, jak správně psát k revizím popisky. Na to je totiž úzus, který téměř všichni programátoři respektují: na prvním řádku je krátké shrnutí změn, následuje prázdný řádek a pak detailnější popis důvodů ke změně a případně změny samotné. Snaž se délku řádků držet do zhruba 70 znaků; vodítkem můžou být předvyplněné řádky začínající #. Nemá cenu popisovat, co je jasné ze změn samotných, zajímavé jsou hlavně širší souvislosti a důvody ke změnám. Cokoli, co může přijít vhod, až se změny bude snažit někdo pochopit. (Ten někdo můžeš být klidně ty, za pár měsíců.)

Můj popisek bude znít takhle:

Rozdělení dlouhých řádků

Verše básně se většinou píšou na jednotlivé řádky. Myslím, že
takhle se to líp čte. (Ale co si budeme povídat, hlavní 
důvod je ukázat, co dělá git diff.)

Nebude-li se ti někdy dařit shrnout změnu v 70 znacích, zamysli se, jestli neděláš moc velkou změnu najednou – např. "změna řetězce X a dopsání nového cyklu Y" by bylo lepší uložit jako dvě různé revize.

Pomocí git commit vytvoř druhou revizi. Pak ji zkontroluj:

$ git show
commit 81cbabb3bd3cd2f3896dd41b20012c44dbd69031
Author: Adéla Novotná <adela.novotna@example.cz>
Date:   Mon Mar 20 14:51:34 2017 +0100

    Rozdělení dlouhých řádků

    Verše básně se většinou píšou na jednotlivé řádky. Myslím, že
    takhle se to líp čte. (Ale co si budeme povídat, hlavní
    důvod je ukázat, co dělá git diff.)

diff --git a/basnicka.txt b/basnicka.txt
index 558d133..24e2384 100644
--- a/basnicka.txt
+++ b/basnicka.txt
@@ -1,6 +1,9 @@
-Holka modrooká, nesedávej u potoka
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej u potoka
+Holka modrooká
+Nesedávej tam
 
 V potoce je hastrmánek
 Zatahá tě za copánek
-Holka modrooká, nesedávej tam
+Holka modrooká
+Nesedávej tam

Diagram

Pro lepší pochopení, co dělají jednotlivé příkazy a v jakém stavu můžou být soubory/změny, přikládám tento diagram:

Diagram revizí

Log

Teď, když máme za sebou první(ch) pár revizí, si ukážeme několik příkazů, které nám umožní se v nich orientovat. První z nich je git log.

$ git log
commit 81cbabb3bd3cd2f3896dd41b20012c44dbd69031
Author: Adéla Novotná <adela.novotna@example.cz>
Date:   Mon Mar 20 14:51:34 2017 +0100

    Rozdělení dlouhých řádků

    Verše básně se většinou píšou na jednotlivé řádky. Myslím, že
    takhle se to líp čte. (Ale co si budeme povídat, hlavní
    důvod je ukázat, co dělá git diff.)

commit 1a009f4267d5a6ab7ece87cb7514f5b803692e39
Author: Adéla Novotná <adela.novotna@example.cz>
Date:   Mon Mar 20 14:51:34 2017 +0100

    První revize

Git log vypíše všechny revize od té nejnovější až po úplný začátek projektu.

Až budeš mít verzí tolik, že se nevejdou najednou na obrazovku, můžeš se v logu pohybovat pomocí šipek a PgUp/PgDn. „Ven“ se dostaneš klávesou q.

Je spousta možností jak vypisovat historii pomocí git log. Všechno je podrobně – možná až moc podrobně – popsáno v dokumentaci; stačí zadat git help log. „Ven“ z dokumentace se opět dostaneš klávesou q.

Já často používám git log --oneline --graph --decorate --cherry-mark --boundary. Chceš-li tyhle možnosti studovat, začni v tomto pořadí a dej si pauzu vždycky, když přestaneš rozumět. :)

Když se na nějakou verzi budeš chtít podívat podrobněji, napiš git show 5ff0b, kde místo 5ff0b uveď prvních několik čísel z označení revize.

gitk

Z příkazové řádky se dá vyčíst všechno potřebné, ale chce to trochu praxe. Někdy je přehlednější použít grafické „klikátko“ jménem gitk, které se dá spustit příkazem gitk --all:

$ gitk --all

Tenhle program vypadá celkem šeredně (skoro jako by ho psali programátoři, které místo designu zajímá, co je „vevnitř“), ale pro naše účely postačí. Zkus se v něm trochu zorientovat, pak ho zavři, udělej dalších pár revizí a koukni se na ně přes git log a gitk --all.

Závěr

A to je všechno, co z Gitu zatím budeš potřebovat. Vždycky, když uděláš git add soubor a git commit, aktuální verze souborů se uloží a už nejde (jednoduše) smazat – pokud nesmažeš celý adresář .git. Jednotlivé verze a změny od posledního uložení, si umíš i prohlížet.

Možná to všechno zní jako zbytečně moc práce. Máš tak trochu pravdu – naše projekty jsou zatím dost malé na to, aby se jen pro ně vyplatilo učit Git. Ale je dobré ho používat už od začátku. Až bude správa verzí opravdu potřeba, bude se tenhle trénink hodit.

Takže odteď, kdykoliv uděláš v rámci PyLadies funkční verzi nějakého programu, pomocí git add a git commit si ji ulož do Gitu.