1 [[!meta title="Verzovací systém Git"]]
8 Naučit se pracovat s verzovacím systémem [Git][git]. Jedná se o velmi
9 rozšířený verzovací systém používaný mnoha open source projekty.
10 Konkrétně nás bude zajímat:
12 * využití Gitu pro distribuovaný vývojový model, který je praktikován
13 mnoha open source projekty,
14 * efektivní prohledávání historie projektu, které je užitečné
15 například při rozhodování, jak správně vyřešit určitý konflikt a
18 [git]:http://git-scm.com/
23 Git je velmi univerzální nástroj pro správu a synchronizaci dat
24 v souborech. Kromě verzování softwaru ho lidé používají
25 k [mnoha dalším činnostem][gitsurvey-usedfor]. Jedna z často
26 zmiňovaných nevýhod Gitu je, že oproti jiným verzovacím systémům je
27 těžší se ho naučit a používat. Možným důvodem je to, že git nabízí
28 větší funkcionalitu než většina ostatních systémů, která se ale
29 využije jen ve speciálních případech – například jen u extrémně
30 velkých projektů jako Linuxové jádro. Ať už to tak je, nebo ne, faktem
31 je, že Git se neustále vyvíjí a mnoho úsilí je věnováno právě zlepšení
32 uživatelské přivětivosti.
34 [gitsurvey-usedfor]:http://www.survs.com/app/7/wo/GffJpx48NlVaG9rZZGKsI0/0.0.0.7.7.3.3.1.1.5.1.1.1.9.1
36 Pro pochopení Gitu je důležité mít základní představu o tom, jak Git
37 pracuje s větvemi, což bylo popsáno v [[přednášce|prednasky/intro-to-git.pdf]]
38 na slidech "*Working on branches*" a "*Working with remotes*".
40 V tomto cvičení budeme opět pracovat s projektem
41 [Midnight commander][mc] z [[1. cvičení|1]]. Pokud s gitem začínáte,
42 doporučuji v průběhu jednotlivých kroků kontrolovat stav repozitáře
43 pomocí grafických nástrojů:
45 * Příkaz `gitk` zobrazuje graficky historii a dovoluje její
46 interaktivní procházení. Přijímá stejné volby jako `git log`, takže
47 v příkazech níže ho můžete použít i pro "vizualizaci" výstupu `git
50 * Příkaz `git gui` je grafický nástroj částečně nahrazující příkazy
51 `git status` a `git commit`. Pomocí menu je možné provádět i další
52 operace jako např. vytváření větví a práce se vzdálenými repozitáři.
54 * Dále existuje ještě spousta dalších [nástrojů][tools]. Já osobně používám
55 kromě výše zmíněných příkazů ještě `tig` a `qgit`.
57 Dále se vám určitě bude hodit dokumentace:
62 [tools]:http://git-scm.com/docs/git-tools
67 1. Základní nastavení. Aby vaše commity obsahovaly správné údaje o
68 vás, nastavte si jméno a email:
70 git config --global user.name "Your Name Comes Here"
71 git config --global user.email you@yourdomain.example.com
75 1. Předpokládáme, že máte zdrojové kódy midnight commanderu někde na
76 disku, takže se přesuňte do adresáře s nimi.
83 2. Možná budete chtít zachovat vaší práci z prvního cvičení. Uložíme
84 jí do nové větve *cviceni1*. Nejprve se ale podíváme v jakém stavu
91 # Changes not staged for commit:
92 # (use "git add <file>..." to update what will be committed)
93 # (use "git checkout -- <file>..." to discard changes in working directory)
95 # modified: lib/keybind.h
96 # modified: src/filemanager/midnight.c
99 # (use "git add <file>..." to include in what will be committed)
103 no changes added to commit (use "git add" and/or "git commit -a")
104 Vidíme, že pracujeme na větvi *master* a vzhledem k verzi uložené v
105 repozitáři máme několik změněných souborů.
107 [mc]:http://www.midnight-commander.org/
109 3. Vytvoříme větev *cviceni1* a přepneme se na ni:
111 git checkout -b cviceni1
113 Nyní už by měl `git status` ukazovat že pracujeme s větví
116 4. Nyní provedeme *commit*:
118 git commit -a -m 'Zmeny z prvniho cviceni'
120 Parametrem `-a` říkáme, že "commitujeme" vše (all) a `-m` udává
121 komentář ke commitu (message). Kdybychom `-m` vynechali, git spustí
122 editor a nechá nás napsat zprávu v něm.
124 > *Poznámka:* Pokud vám nevyhovuje výchozí editor (většinou `vi`),
125 > nastavte si, že chcete používat jiný editor (např. `pico`):
127 > git config --global core.editor pico
129 5. Nyní se přepneme zpět na větev *master*:
132 V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
134 6. Seznam větví v našem repozitáři zjistíme příkazem
137 Aktuální větev je označena hvězdičkou `*`.
139 Práce s více vzdálenými repozitáři
140 ----------------------------------
142 Doposud jsme pracovali pouze s jedním vzdáleným repozitářem. Mezi velké
143 výhody gitu (a ostatních distribuovaných verzovacích systémů) patří
144 schopnost pracovat s více vzdálenými repozitáři.
146 1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
150 Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
153 1. Pokud chceme nějaký vzdálený repozitář používat často,
154 vyplatí se ho pojmenovat krátkým jménem (v příkladu níže *osp*),
155 abychom nemuseli pořád psát dlouhé URL:
157 git remote add osp ssh://git@rtime.felk.cvut.cz/osp/mc
159 V tomto repozitáři je uloženo zadání dnešní úlohy. Abyste se k němu
160 dostali, musí server znát váš veřejný SSH klíč. Jak toho docílit
161 najdete na [[samostatné stránce|rtime-git-ssh-key]]. Přístup k
162 repozitářům na serveru rtime budete potřebovat i v písemce. **Proto
163 vám důrazně doporučujeme zprovoznit přístup už na tomto cvičení,
164 abyste při písemce neztráceli čas.**
166 2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
169 V případě úspěchu bude výstup vypadat následovně:
171 remote: Counting objects: 34, done.
172 remote: Compressing objects: 100% (17/17), done.
173 remote: Total 20 (delta 17), reused 6 (delta 3)
174 Unpacking objects: 100% (20/20), done.
175 From ssh://rtime.felk.cvut.cz/osp/mc
176 * [new branch] master -> osp/master
177 * [new branch] only-directories -> osp/only-directories
178 * [new branch] only-directories-old -> osp/only-directories-old
180 3. Příkaz nám vypíše, že v repozitáři byly dvě nové větve. Všechny
181 větve ze vzdálených repozitářů vypíšeme příkazem
184 Zjednodušeně řečeno, jediný rozdíl mezi lokální a vzdálenou větví
185 je v tom, že jméno vzdálené větve má prefix `<remote>/` (v našem
186 případě `origin/` nebo `osp/`).
188 4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
190 git log osp/only-directories ^master
191 git log master..osp/only-directories
192 Tyto dva příkazy jsou ekvivalentní a vypisují commity, které jsou
193 ve větvi *osp/only-directories* a zároveň nejsou (^) ve větvi *master*.
195 Chcete-li vidět i změny v kódu použijte jeden z následujících příkazů:
197 git log -p osp/only-directories ^master
198 gitk osp/only-directories ^master
200 6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
201 je výchozí a proto ho nemusíme zadávat:
204 Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
206 git log master..origin/master
208 Slučování větví (merge)
209 -----------------------
211 Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
212 Můžou při slučování nastat tři situace:
214 * *Already up-to-date* je situace, kdy už je větev, kterou chceme
215 sloučit, dosažitelná z aktuální větve (už byla sloučena v
216 minulosti). Při sloučení nedojde k žádné změně.
217 * *Fast-forward* je opak předchozí situace, tj. aktuální větev je
218 dosažitelná ze slučované větve. To odpovídá situaci, kdy
219 aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
220 na poslední commit) posunuta na novější verzi.
221 * *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
222 o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
224 Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
225 obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
227 1. Zkuste provést sloučení své větve *master* s *origin/master*
229 git merge origin/master
230 Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
232 git merge origin/master
233 Updating 0ebd30c..a99dc51
236 contrib/Makefile.am | 9 +-
238 Toto je velmi častá operace a proto lze operace `fetch` a `merge`
239 nahradit jedním příkazem
242 2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
243 založit si na to samostatnou větev. Dnešním úkolem bude sloučit
244 větev *osp/only-directories* s větví *master* a protože to není
245 triviální založte si na to novou větev:
247 git checkout -b homework
248 3. Pokud provedete sloučení
250 git merge osp/only-directories
251 Výsledek bude vypadat pravděpodobně takto:
253 Auto-merging doc/man/mc.1.in
254 Auto-merging src/filemanager/find.c
255 CONFLICT (content): Merge conflict in src/filemanager/find.c
256 Automatic merge failed; fix conflicts and then commit the result.
258 Vidíme, že se automaticky povedlo sloučit změny v souboru
259 `doc/mc.1.in`, ale při slučování změn ve `src/find.c` už takové
260 štěstí nemáme a výsledkem je konflikt.
266 Konflikt lze řešit několika způsoby (viz také `git merge --help`):
268 * Vzdáme to a vrátíme se k verzi před slučováním
272 * Konflikt vyřešíme a oznámíme to gitu příkazy `git add` a `git
273 commit` (jak nám git napovídá v hláškách)
275 V průběhu řešení konfliktu je užitečné používat příkaz `git status`,
276 Abychom zjistili, co je ještě potřeba vyřešit. V našem případě vypadá
280 # Changes to be committed:
282 # modified: doc/man/mc.1.in
285 # (use "git add/rm <file>..." as appropriate to mark resolution)
287 # both modified: src/filemanager/find.c
289 Konflikt lze řešit následujícími způsoby:
291 * Soubor s konfliktem otevřeme v textovém editoru a najdeme sekvence
292 `<<<<<<<<`, `=========` a `>>>>>>>>`, kterými jsou označené
293 jednotlivé konfliktní oblasti. Tato místa musíme opravit tak, aby
294 kód dával smysl a poté zmíněné sekvence znaků smažeme.
295 * Použijeme příkaz `git mergetool`, který spouští grafický nástroj
296 (např. [kdiff3][kdiff3]), který nám se slučováním pomůže.
298 `kdiff3` vedle sebe zobrazuje 3 různé verze projektu: poslední
299 společná verze (base), verzi z větve před slučováním (local) a verzi
300 ze slučované větve (remote), tj. té uvedené jako parametr v příkazu
303 Ve spodní části obrazovky je pak vidět výsledek slučování, který
304 můžeme měnit buď přímou editací a nebo výběrem jednotlivých verzí
305 pomocí tlačítek A, B a C. V tomto okně je potřeba zbavit se všech
306 řádek, které mají v levém sloupci `?` – tj. konfliktů.
308 Při řešení konfliktů nám může pomoct i příkaz `gitk --merge`, který
309 zobrazí pouze commity, které modifikovaly konfliktní soubory.
310 Jednoduše tam můžeme zjistit, které změny konflikt způsobily.
312 Git obsahuje poměrně jednoduchý algoritmus (v porovnání s jinými
313 verzovacími systémy) pro slučování různých verzí souborů. Některým
314 studentům se to nelíbí a stěžují si. Přečtěte si
315 [názor Linuse Torvaldse][mergealg], proč tomu tak je.
317 [mergealg]:http://stackoverflow.com/questions/612580/how-does-git-solve-the-merging-problem/612747#612747
319 [kdiff3]:http://kdiff3.sourceforge.net/
324 K tomu, aby výsledky vaší práce na open source projektech byly snadno
325 dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
326 si budou moct ostatní vaše změny stáhnout.
328 1. Zaregistrujte se na [GitHubu](https://github.com/). V závislosti na
329 tom, jakým protokolem chcete k repozitářům na GitHubu přistupovat
330 si nastavte buď [password caching][passcache] (pro HTTP) nebo
331 [SSH klíče][sshkeys] (pro SSH).
333 [passcache]:https://help.github.com/articles/set-up-git#password-caching
334 [sshkeys]:https://help.github.com/articles/generating-ssh-keys
336 2. Vytvoření repozitáře na GitHubu. Můžete založit buď
337 [nový projekt][new] nebo udělat tzv. "fork" existujícího projektu.
339 Pro účely tohoto cvičení si [založte fork][forkmc]
340 [Midnight commanderu][osp-mc]. Do takto vytvořeného repozitáře pak
341 nahrajete úkol z dnešního cvičení.
343 3. Do svého repozitáře na GitHubu nahrajete větev z lokálního
344 repozitáře některým z těchto způsobů:
346 git remote add github https://github.com/<mujlogin>/mc.git
347 git push github HEAD:homework
350 git push https://github.com/<mujlogin>/mc.git homework
353 git push ssh://git@github.com/<mujlogin>/mc.git homework
355 [new]:https://github.com/new
356 [osp-mc]:https://github.com/CTU-OSP/mc
357 [forkmc]:https://github.com/CTU-OSP/mc/fork
363 Proveďte sloučení větve `ssh://git@rtime.felk.cvut.cz/osp/mc
364 only-directories` s aktuální vývojovou větví Midnight Commanderu
365 (`origin/master`). Výsledek musí jít zkompilovat a musí obsahovat
366 funkcionalitu přidanou do větve `only-directories`. Výsledek uložte do
367 [vámi vytvořeného repozitáře (forku) na GitHubu][forkmc] do větve