1 [[!meta title="Verzovací systém Git"]]
8 Naučit se pracovat verzovacím systémem [Git](http://git-scm.com/),
10 * distribuovaným vývojový model
11 * práce s několika větvemi
17 V tomto cvičení budeme opět pracovat s projektem
18 [Midnight commander][mc] z [[1. cvičení|1]]. Pokud s gitem začínáte,
19 doporučuji v průběhu jednotlivých kroků kontrolovat stav repozitáře
20 pomocí grafických nástrojů.
22 * Příkaz `gitk` zobrazuje graficky historii a dovoluje její
23 interaktivní procházení. Přijímá stejné volby jako `git log`, takže
24 v příkazech níže ho můžete použít i pro vizualizaci výstupu `git
27 * Příkaz `git gui` je grafický nástroj částečně nahrazující příkazy
28 `git status` a `git commit`. Pomocí menu je možné provádět i další
29 operace jako např. vytváření větví a práce se vzdálenými repozitáři.
31 * Dále existuje ještě spousta dalších [nástrojů][tools]. Já osobně používám
32 kromě výše zmíněných příkazů ještě `tig` a `qgit`.
34 Dále se vám určitě bude hodit dokumentace:
38 [tools]:http://git-scm.com/tools
43 1. Základní nastavení. Aby vaše commity obsahovaly správné údaje o
44 vás, nastavte si jméno a email:
46 git config --global user.name "Your Name Comes Here"
47 git config --global user.email you@yourdomain.example.com
51 1. Předpokládáme, že máte zdrojové kódy midnight commanderu někde na
52 disku, takže se přesuňte do adresáře s nimi.
59 2. Možná budete chtít zachovat vaší práci z prvního cvičení. Uložíme
60 jí do nové větve *cviceni1*. Nejprve se ale podíváme v jakém stavu
67 # Changed but not updated:
68 # (use "git add <file>..." to update what will be committed)
69 # (use "git checkout -- <file>..." to discard changes in working directory)
72 # modified: po/be-tarask.po
75 # modified: src/cmddef.h
76 # modified: src/main.c
77 Vidíme, že pracujeme na větvi *master* a vzhledem k verzi uložené v
78 repozitáři máme několik změněných souborů.
80 [mc]:http://www.midnight-commander.org/
82 1. Midnight commander má bohužel jednu vlastnost, která může ztížit
83 vaše začátky s gitem. Při kompilaci dojde k automatickému
84 přegenerování některých souborů v repozitáři a git potom hlásí, že
85 jsme tyto soubory změnili a "otravuje" s nimi při každém commitu.
87 Naštěstí existuje možnost jak gitu říct, že nás změny v některých
90 git update-index --assume-unchanged $(git ls-files po m4)
92 Příkaz `git ls-files po m4` vypíše všechny soubory z adresářů *po*
93 a *m4*, které jsou spravované gitem a příkazem `git update-index
94 --assume-unchanged` pak gitu sdělíme, aby si do indexu poznamenal,
95 že tyto soubory má ignorovat.
97 > *Poznámka:* Možná víte o souborech *.gitignore* (viz `man
98 > gitignore`), které slouží k podobnému účelu. Ostatně midnight
99 > commander je také využívá, jak se můžete snadno přesvědčit:
103 > Soubory *.gitignore* se ale vztahují pouze na soubory, které
104 > ještě nejsou součástí repozitáře, což není případ výše zmíněných
107 3. Vytvoříme větev *cviceni1* a přepneme se na ni:
109 git checkout -b cviceni1
111 Nyní už by měl `git status` ukazovat že pracujeme s větví
112 *cviceni1* a vidíme pouze námi modifikované soubory.
114 4. Nyní provedeme *commit*:
116 git commit -a -m 'Zmeny z prvniho cviceni'
118 Parametrem `-a` říkáme, že "commitujeme" vše (all) a `-m` udává
119 komentář ke commitu (message). Kdybychom `-m` vynechali, git spustí
120 editor a nechá nás napsat zprávu v něm.
122 > *Poznámka:* Pokud vám nevyhovuje výchozí editor (většinou `vi`),
123 > nastavte si, že chcete používat jiný editor (např. `pico`):
125 > git config --global core.editor pico
127 5. Nyní se přepneme zpět na větev *master*:
130 V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
132 6. Seznam větví v našem repozitáři zjistíme příkazem
135 Aktuální větev je označena hvězdičkou `*`.
137 Práce s více vzdálenými repozitáři
138 ----------------------------------
140 Do teď jsme pracovali pouze s jedním vzdáleným repozitářem. Mezi velké
141 výhody gitu (a ostatních distribuovaných verzovacích systémů) patří
142 schopnost pracovat s více vzdálenými repozitáři.
144 1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
148 Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
151 1. Pokud chceme nějaký konkrétní vzdálený repozitář používat často,
152 vyplatí se ho pojmenovat krátkým jménem (v příkladu níže *osp*),
153 abychom nemuseli pořád psát dlouhé URL:
155 git remote add osp git://repo.or.cz/midnight-commander/osp.git
157 2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
160 3. Příkaz nám vypíše, že v repozitáři byly dvě nové větve. Všechny
161 větve ze vzdálených repozitářů vypíšeme příkazem
164 Zjednodušeně řečeno, jediný rozdíl mezi lokální a vzdálenou větví
165 je v tom, že vzdálená větev má prefix `<remote>/`.
167 4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
169 git log osp/only-directories ^master
170 git log master..osp/only-directories
171 Tyto dva příkazy jsou ekvivalentní a vypisují commity, které jsou
172 ve větvi *osp/only-directories* a zároveň nejsou ve větvi *master*.
174 Chcete-li vidět i změny v kódu použijte jeden z následujících příkazů
175 git log -p osp/only-directories ^master
176 gitk osp/only-directories ^master
178 6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
179 je výchozí a proto ho nemusíme zadávat:
182 Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
184 git log master..origin/master
186 Slučování větví (merge)
187 -----------------------
189 Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
190 můžou při slučování nastat tři situace:
192 * *Already up-to-date* je situace, kdy už je větev, kterou chceme
193 sloučit, dosažitelná z aktuální větve (už byla sloučena v
194 minulosti). Při sloučení nedojde k žádné změně.
195 * *Fast-forward* je opak předchozí situace, tj. aktuální větev je
196 dosažitelná ze slučované větve. To odpovídá situaci, kdy
197 aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
198 na poslední commit) posunuta na novější verzi.
199 * *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
200 o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
202 Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
203 obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
205 1. Zkuste provést sloučení vaší větve *master* s *origin/master*
207 git merge origin/master
208 Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
210 git merge origin/master
211 Updating 0ebd30c..a99dc51
214 contrib/Makefile.am | 9 +-
216 Toto je velmi častá operace a proto lze oprace `fetch` a `merge`
217 nahradit jedním příkazem
219 2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
220 založit si na to samostatnou větev. Dnešním úkolem bude sloučit
221 větev *osp/only-directories* s větví *master* a protože to není
222 triviální založte si na to novou větev:
224 git checkout -b homework
225 3. Pokud provedete sloučení
227 git merge osp/only-directories
228 Výsledek bude vypadat pravděpodobně takto:
229 Renaming doc/mc.1.in => doc/man/mc.1.in
230 Auto-merging doc/man/mc.1.in
231 Auto-merging src/find.c
232 CONFLICT (content): Merge conflict in src/find.c
233 Automatic merge failed; fix conflicts and then commit the result.
234 Vidíme, že git správně zjistil, že soubor `doc/mc.1.in` byl
235 v novější verzi přejmenován a provedl sloučení až po přejmenování.
236 Při slučování změn ve `src/find.c` už takové štěstí nemáme a
237 výsledkem je konflikt.
243 Konflikt lze řešit několika způsoby (viz také `git merge --help`):
245 * Vzdáme to a vrátíme se k verzi před slučováním
249 * Konflikt vyřešíme a oznámíme to gitu příkazy `git add` a `git
250 commit` (jak nám git napovídá v hláškách)
252 V průběhu řešení konfliktu je užitečné používat příkaz `git status`,
253 abychom zjistili co je ještě potřeba vyřešit. V našem případě vypadá
254 výstup zhruba takhle:
256 # On branch merge-assignment
257 # Changes to be committed:
259 # modified: doc/man/mc.1.in
262 # (use "git add/rm <file>..." as appropriate to mark resolution)
264 # both modified: src/find.c
270 * editor a <<<<<<<< ========= >>>>>>>>
274 Repozitář na repo.or.cz
275 ---------------------------
277 K tomu, aby výsledky vaší práce na open source projektech byly snadno
278 dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
279 si budou moct ostatní vaše změny stáhnout.
281 1. [Zaregistrujte][reg] se na [repo.or.cz][roc]. K repozitáři na
282 repo.or.cz se přistupuje protokolem SSH a autorizace se provádí na
283 základě veřejných klíčů.
285 1. Pokud žádný klíč nemáte, vytvořte si ho příkazem
289 Příkaz se vás zeptá kam klíč uložit. Výchozí volba vám zpočátku
290 bude stačit. Dále se zeptá na heslo (passphrase) k vašemu
291 privátnímu klíči. Pokud žádné heslo nezadáte, bude se moct
292 kdokoli, kdo se dostane k souboru s vaším klíčem (např.
293 administrátor školních serverů), autorizovat jako vy.
295 2. Pokud jste se rozhodli chránit klíč heslem, je otravné zadávat
296 heslo vždy, když klíč používáte. Naštěstí existuje program
297 `ssh-agent`, který uchovává odheslované klíče v paměti a
298 poskytuje je vždy, když je nějaký oprávněný program potřebuje.
299 Vy tak zadáte heslo jen jednou a to když předáváte klíč
300 ssh-agentovi příkazem
304 [reg]:http://repo.or.cz/reguser.cgi
305 [roc]:http://repo.or.cz/
307 2. Vytvoření repozitáře na repo.or.cz.
309 Můžete založit buď [nový projekt][new] a nebo udělat tzv.
310 [fork existujícího projektu][forkmc]. Pro oba typy projektů můžete
311 zvolit zda bude repozitář pouze automaticky aktualizovanou kopí
312 jiného repozitáře (*mirror*) a nebo zda-li bude možné do něj přímo
313 ukládat nové commity (*push*).
315 Pro účely tohoto cvičení si
316 [založte fork Midnight commanderu][forkmc] v *Push módu*, který se
317 bude jmenovat podle vašeho loginu. Do tohoto repozitáře pak
318 nahrajete úkol z dnešního cvičení.
320 3. Do vašeho vzdáleného repozitáře můžete nahrát vaší větev některým z
323 git push ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git homework
326 git remote add repo-or-cz ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git
327 git push repo-or-cz homework
329 [new]:http://repo.or.cz/regproj.cgi
330 [forkmc]:http://repo.or.cz/regproj.cgi?fork=midnight-commander/osp.git
335 Proveďte sloučení větve `git://repo.or.cz/midnight-commander/osp.git
336 only-directories` s aktuální vývojovou větví (`master`). Výsledek
337 uložte do [vámi vytvořeného repozitáře (forku) na repo.or.cz][forkmc]