--- /dev/null
+[[!meta title="Verzovací systém Git"]]
+
+[[!toc levels=2]]
+
+Cíl
+===
+
+Naučit se pracovat verzovacím systémem [Git](http://git-scm.com/),
+
+* distribuovaným vývojový model
+* práce s několika větvemi
+...
+
+Úvod
+====
+
+V tomto cvičení budeme opět pracovat s projektem
+[Midnight commander][mc] z [[1. cvičení|1]]. Pokud s gitem začínáte,
+doporučuji v průběhu jednotlivých kroků kontrolovat stav repozitáře
+pomocí grafických nástrojů.
+
+* Příkaz `gitk` zobrazuje graficky historii a dovoluje její
+ interaktivní procházení. Přijímá stejné volby jako `git log`, takže
+ v příkazech níže ho můžete použít i pro vizualizaci výstupu `git
+ log`.
+
+* Příkaz `git gui` je grafický nástroj částečně nahrazující příkazy
+ `git status` a `git commit`. Pomocí menu je možné provádět i další
+ operace jako např. vytváření větví a práce se vzdálenými repozitáři.
+
+* Dále existuje ještě spousta dalších [nástrojů][tools]. Já osobně používám
+ kromě výše zmíněných příkazů ještě `tig` a `qgit`.
+
+Dále se vám určitě bude hodit dokumentace:
+ git help <příkaz>
+ git <příkaz> --help
+
+[tools]:http://git-scm.com/tools
+
+Postup
+======
+
+1. Základní nastavení. Aby vaše commity obsahovaly správné údaje o
+ vás, nastavte si jméno a email:
+
+ git config --global user.name "Your Name Comes Here"
+ git config --global user.email you@yourdomain.example.com
+
+
+
+1. Předpokládáme, že máte zdrojové kódy midnight commanderu někde na
+ disku, takže se přesuňte do adresáře s nimi.
+
+ cd ~/mc
+
+Lokální větve
+-------------
+
+2. Možná budete chtít zachovat vaší práci z prvního cvičení. Uložíme
+ jí do nové větve *cviceni1*. Nejprve se ale podíváme v jakém stavu
+ máme zdrojové kódy:
+
+ git status
+ Dostaneme něco jako:
+
+ # On branch master
+ # Changed but not updated:
+ # (use "git add <file>..." to update what will be committed)
+ # (use "git checkout -- <file>..." to discard changes in working directory)
+ #
+ # modified: po/az.po
+ # modified: po/be-tarask.po
+ # modified: po/be.po
+ # ...
+ # modified: src/cmddef.h
+ # modified: src/main.c
+ Vidíme, že pracujeme na větvi *master* a vzhledem k verzi uložené v
+ repozitáři máme několik změněných souborů.
+
+[mc]:http://www.midnight-commander.org/
+
+1. Midnight commander má bohužel jednu vlastnost, která může ztížit
+ vaše začátky s gitem. Při kompilaci dojde k automatickému
+ přegenerování některých souborů v repozitáři a git potom hlásí, že
+ jsme tyto soubory změnili a "otravuje" s nimi při každém commitu.
+
+ Naštěstí existuje možnost jak gitu říct, že nás změny v některých
+ souborech nezajímají:
+
+ git update-index --assume-unchanged $(git ls-files po m4)
+
+ Příkaz `git ls-files po m4` vypíše všechny soubory z adresářů *po*
+ a *m4*, které jsou spravované gitem a příkazem `git update-index
+ --assume-unchanged` pak gitu sdělíme, aby si do indexu poznamenal,
+ že tyto soubory má ignorovat.
+
+ > *Poznámka:* Možná víte o souborech *.gitignore* (viz `man
+ > gitignore`), které slouží k podobnému účelu. Ostatně midnight
+ > commander je také využívá, jak se můžete snadno přesvědčit:
+ >
+ > cat .gitignore
+ >
+ > Soubory *.gitignore* se ale vztahují pouze na soubory, které
+ > ještě nejsou součástí repozitáře, což není případ výše zmíněných
+ > souborů.
+
+3. Vytvoříme větev *cviceni1* a přepneme se na ni:
+
+ git checkout -b cviceni1
+
+ Nyní už by měl `git status` ukazovat že pracujeme s větví
+ *cviceni1* a vidíme pouze námi modifikované soubory.
+
+4. Nyní provedeme *commit*:
+
+ git commit -a -m 'Zmeny z prvniho cviceni'
+
+ Parametrem `-a` říkáme, že "commitujeme" vše (all) a `-m` udává
+ komentář ke commitu (message). Kdybychom `-m` vynechali, git spustí
+ editor a nechá nás napsat zprávu v něm.
+
+ > *Poznámka:* Pokud vám nevyhovuje výchozí editor (většinou `vi`),
+ > nastavte si, že chcete používat jiný editor (např. `pico`):
+ >
+ > git config --global core.editor pico
+
+5. Nyní se přepneme zpět na větev *master*:
+
+ git checkout master
+ V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
+
+6. Seznam větví v našem repozitáři zjistíme příkazem
+
+ git branch
+ Aktuální větev je označena hvězdičkou `*`.
+
+Práce s více vzdálenými repozitáři
+----------------------------------
+
+Do teď jsme pracovali pouze s jedním vzdáleným repozitářem. Mezi velké
+výhody gitu (a ostatních distribuovaných verzovacích systémů) patří
+schopnost pracovat s více vzdálenými repozitáři.
+
+1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
+
+ git remote -v
+
+ Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
+ URL.
+
+1. Pokud chceme nějaký konkrétní vzdálený repozitář používat často,
+ vyplatí se ho pojmenovat krátkým jménem (v příkladu níže *osp*),
+ abychom nemuseli pořád psát dlouhé URL:
+
+ git remote add osp git://repo.or.cz/midnight-commander/osp.git
+
+2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
+
+ git fetch osp
+3. Příkaz nám vypíše, že v repozitáři byly dvě nové větve. Všechny
+ větve ze vzdálených repozitářů vypíšeme příkazem
+
+ git branch -r
+ Zjednodušeně řečeno, jediný rozdíl mezi lokální a vzdálenou větví
+ je v tom, že vzdálená větev má prefix `<remote>/`.
+
+4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
+
+ git log osp/only-directories ^master
+ git log master..osp/only-directories
+ Tyto dva příkazy jsou ekvivalentní a vypisují commity, které jsou
+ ve větvi *osp/only-directories* a zároveň nejsou ve větvi *master*.
+
+ Chcete-li vidět i změny v kódu použijte jeden z následujících příkazů
+ git log -p osp/only-directories ^master
+ gitk osp/only-directories ^master
+
+6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
+ je výchozí a proto ho nemusíme zadávat:
+
+ git fetch
+ Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
+
+ git log master..origin/master
+
+Slučování větví (merge)
+-----------------------
+
+Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
+můžou při slučování nastat tři situace:
+
+* *Already up-to-date* je situace, kdy už je větev, kterou chceme
+ sloučit, dosažitelná z aktuální větve (už byla sloučena v
+ minulosti). Při sloučení nedojde k žádné změně.
+* *Fast-forward* je opak předchozí situace, tj. aktuální větev je
+ dosažitelná ze slučované větve. To odpovídá situaci, kdy
+ aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
+ na poslední commit) posunuta na novější verzi.
+* *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
+ o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
+
+Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
+obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
+
+1. Zkuste provést sloučení vaší větve *master* s *origin/master*
+
+ git merge origin/master
+ Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
+
+ git merge origin/master
+ Updating 0ebd30c..a99dc51
+ Fast forward
+ configure.ac | 1 +
+ contrib/Makefile.am | 9 +-
+ ...
+ Toto je velmi častá operace a proto lze oprace `fetch` a `merge`
+ nahradit jedním příkazem
+ git pull
+2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
+ založit si na to samostatnou větev. Dnešním úkolem bude sloučit
+ větev *osp/only-directories* s větví *master* a protože to není
+ triviální založte si na to novou větev:
+
+ git checkout -b homework
+3. Pokud provedete sloučení
+
+ git merge osp/only-directories
+ Výsledek bude vypadat pravděpodobně takto:
+ Renaming doc/mc.1.in => doc/man/mc.1.in
+ Auto-merging doc/man/mc.1.in
+ Auto-merging src/find.c
+ CONFLICT (content): Merge conflict in src/find.c
+ Automatic merge failed; fix conflicts and then commit the result.
+ Vidíme, že git správně zjistil, že soubor `doc/mc.1.in` byl
+ v novější verzi přejmenován a provedl sloučení až po přejmenování.
+ Při slučování změn ve `src/find.c` už takové štěstí nemáme a
+ výsledkem je konflikt.
+
+
+Řešení konfliktů
+----------------
+
+Konflikt lze řešit několika způsoby (viz také `git merge --help`):
+
+* Vzdáme to a vrátíme se k verzi před slučováním
+
+ git reset --hard
+
+* Konflikt vyřešíme a oznámíme to gitu příkazy `git add` a `git
+ commit` (jak nám git napovídá v hláškách)
+
+V průběhu řešení konfliktu je užitečné používat příkaz `git status`,
+abychom zjistili co je ještě potřeba vyřešit. V našem případě vypadá
+výstup zhruba takhle:
+
+ # On branch merge-assignment
+ # Changes to be committed:
+ #
+ # modified: doc/man/mc.1.in
+ #
+ # Unmerged paths:
+ # (use "git add/rm <file>..." as appropriate to mark resolution)
+ #
+ # both modified: src/find.c
+ #
+
+TODO...
+
+* git mergetool
+* editor a <<<<<<<< ========= >>>>>>>>
+* gitk --merge
+
+
+Repozitář na repo.or.cz
+---------------------------
+
+K tomu, aby výsledky vaší práce na open source projektech byly snadno
+dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
+si budou moct ostatní vaše změny stáhnout.
+
+1. [Zaregistrujte][reg] se na [repo.or.cz][roc]. K repozitáři na
+ repo.or.cz se přistupuje protokolem SSH a autorizace se provádí na
+ základě veřejných klíčů.
+
+ 1. Pokud žádný klíč nemáte, vytvořte si ho příkazem
+
+ ssh-keygen
+
+ Příkaz se vás zeptá kam klíč uložit. Výchozí volba vám zpočátku
+ bude stačit. Dále se zeptá na heslo (passphrase) k vašemu
+ privátnímu klíči. Pokud žádné heslo nezadáte, bude se moct
+ kdokoli, kdo se dostane k souboru s vaším klíčem (např.
+ administrátor školních serverů), autorizovat jako vy.
+
+ 2. Pokud jste se rozhodli chránit klíč heslem, je otravné zadávat
+ heslo vždy, když klíč používáte. Naštěstí existuje program
+ `ssh-agent`, který uchovává odheslované klíče v paměti a
+ poskytuje je vždy, když je nějaký oprávněný program potřebuje.
+ Vy tak zadáte heslo jen jednou a to když předáváte klíč
+ ssh-agentovi příkazem
+
+ ssh-add
+
+[reg]:http://repo.or.cz/reguser.cgi
+[roc]:http://repo.or.cz/
+
+2. Vytvoření repozitáře na repo.or.cz.
+
+ Můžete založit buď [nový projekt][new] a nebo udělat tzv.
+ [fork existujícího projektu][forkmc]. Pro oba typy projektů můžete
+ zvolit zda bude repozitář pouze automaticky aktualizovanou kopí
+ jiného repozitáře (*mirror*) a nebo zda-li bude možné do něj přímo
+ ukládat nové commity (*push*).
+
+ Pro účely tohoto cvičení si
+ [založte fork Midnight commanderu][forkmc] v *Push módu*, který se
+ bude jmenovat podle vašeho loginu. Do tohoto repozitáře pak
+ nahrajete úkol z dnešního cvičení.
+
+3. Do vašeho vzdáleného repozitáře můžete nahrát vaší větev některým z
+ těchto způsobů
+
+ git push ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git homework
+ nebo
+
+ git remote add repo-or-cz ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git
+ git push repo-or-cz homework
+
+[new]:http://repo.or.cz/regproj.cgi
+[forkmc]:http://repo.or.cz/regproj.cgi?fork=midnight-commander/osp.git
+
+Zadání
+======
+
+Proveďte sloučení větve `git://repo.or.cz/midnight-commander/osp.git
+only-directories` s aktuální vývojovou větví (`master`). Výsledek
+uložte do [vámi vytvořeného repozitáře (forku) na repo.or.cz][forkmc]
+do větve `homework`.