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 poměrně univerzální nástroj pro správu a synchronizaci dat
24 v souborech. Kromě verzování softwaru ho lidé používají k mnoha dalším
25 činnostem (viz [Git User's Survey 2012, otázka 8][gitsurvey]). Jedna
26 z často zmiňovaných nevýhod Gitu je, že oproti jiným verzovacím
27 systémům je těžší se ho naučit a používat. Možným důvodem je to, že
28 git nabízí větší funkcionalitu než většina ostatních systémů, která se
29 ale 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]:https://www.survs.com/results/QPESOB10/ME8UTHXM4M
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í nebo pracovat se vzdálenými
55 * Dále existuje ještě spousta dalších [nástrojů][tools]. Já osobně používám
56 kromě výše zmíněných příkazů ještě `tig` a `qgit`.
58 Dále se vám určitě bude hodit dokumentace:
63 [tools]:http://git-scm.com/docs/git-tools
68 1. Základní nastavení. Aby vaše commity obsahovaly správné údaje o
69 vás, nastavte si jméno a email:
71 git config --global user.name "Your Name Comes Here"
72 git config --global user.email you@yourdomain.example.com
76 1. Předpokládáme, že máte zdrojové kódy midnight commanderu někde na
77 disku, takže se přesuňte do adresáře s nimi.
84 2. Možná budete chtít zachovat vaší práci z prvního cvičení. Uložíme
85 jí do nové větve *cviceni1*. Nejprve se ale podíváme v jakém stavu
92 # Changes not staged for commit:
93 # (use "git add <file>..." to update what will be committed)
94 # (use "git checkout -- <file>..." to discard changes in working directory)
96 # modified: lib/keybind.h
97 # modified: src/filemanager/midnight.c
100 # (use "git add <file>..." to include in what will be committed)
104 no changes added to commit (use "git add" and/or "git commit -a")
105 Vidíme, že pracujeme na větvi *master* a vzhledem k verzi uložené v
106 repozitáři máme několik změněných souborů.
108 [mc]:http://www.midnight-commander.org/
110 3. Vytvoříme větev *cviceni1* a přepneme se na ni:
112 git checkout -b cviceni1
114 Nyní už by měl `git status` ukazovat že pracujeme s větví
117 4. Nyní provedeme *commit*:
119 git commit -a -m 'Zmeny z prvniho cviceni'
121 Parametrem `-a` říkáme, že "commitujeme" vše (all) a `-m` udává
122 komentář ke commitu (message). Kdybychom `-m` vynechali, git spustí
123 editor a nechá nás napsat zprávu v něm.
125 > *Poznámka:* Pokud vám nevyhovuje výchozí editor (většinou `vi`),
126 > nastavte si, že chcete používat jiný editor (např. `pico`):
128 > git config --global core.editor pico
130 5. Nyní se přepneme zpět na větev *master*:
133 V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
135 6. Seznam větví v našem repozitáři zjistíme příkazem
138 Aktuální větev je označena hvězdičkou `*`.
140 Práce s více vzdálenými repozitáři
141 ----------------------------------
143 Doposud jsme pracovali pouze s jedním vzdáleným repozitářem. Mezi velké
144 výhody gitu (a ostatních distribuovaných verzovacích systémů) patří
145 schopnost pracovat s více vzdálenými repozitáři.
147 1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
151 Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
154 1. Pokud chceme nějaký vzdálený repozitář používat často,
155 vyplatí se ho pojmenovat krátkým jménem (v příkladu níže *osp*),
156 abychom nemuseli pořád psát dlouhé URL:
158 git remote add osp ssh://git@rtime.felk.cvut.cz/osp/mc
160 V tomto repozitáři je uloženo zadání dnešní úlohy. Abyste se k němu
161 dostali, musí server znát váš veřejný SSH klíč. Jak toho docílit
162 najdete na [[samostatné stránce|rtime-git-ssh-key]]. Přístup k
163 repozitářům na serveru rtime budete potřebovat i v písemce. **Proto
164 vám důrazně doporučujeme zprovoznit přístup už na tomto cvičení,
165 abyste při písemce neztráceli čas.**
167 2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
170 V případě úspěchu bude výstup vypadat následovně:
172 remote: Counting objects: 34, done.
173 remote: Compressing objects: 100% (17/17), done.
174 remote: Total 20 (delta 17), reused 6 (delta 3)
175 Unpacking objects: 100% (20/20), done.
176 From ssh://rtime.felk.cvut.cz/osp/mc
177 * [new branch] master -> osp/master
178 * [new branch] only-directories -> osp/only-directories
179 * [new branch] only-directories-old -> osp/only-directories-old
181 3. Příkaz nám vypíše, že v repozitáři byly tři nové větve. Všechny
182 větve ze vzdálených repozitářů vypíšeme příkazem
185 Zjednodušeně řečeno, jediný rozdíl mezi lokální a vzdálenou větví
186 je v tom, že jméno vzdálené větve má prefix `<remote>/` (v našem
187 případě `origin/` nebo `osp/`).
189 4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
191 git log osp/only-directories ^master
192 git log master..osp/only-directories
193 Tyto dva příkazy jsou ekvivalentní a vypisují commity, které jsou
194 ve větvi *osp/only-directories* a zároveň nejsou (^) ve větvi *master*.
196 Chcete-li vidět i změny v kódu (patch) použijte jeden
197 z následujících příkazů:
199 git log -p osp/only-directories ^master
200 gitk osp/only-directories ^master
202 Výše uvedené příkazy zobrazují změny provedené jednotlivými
203 commity. Pokud nás zajímá celková změna bez rozdělení na jednotlivé
204 committy, pomůže nám příkaz `git diff`:
206 git diff master..osp/only-directories
207 git diff master osp/only-directories
209 První příkaz zobrazí změny, které obsahuje verze *only-directories* a
210 nejsou ve větvi master. Druhý příkaz zobrazí kompletní rozdíl, tj.
211 i změny, které jsou ve větvi *master* a ne v *only-directories*.
213 6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
214 je výchozí a proto ho nemusíme zadávat:
217 Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
219 git log master..origin/master
221 Slučování větví (merge)
222 -----------------------
224 Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
225 můžou při slučování nastat tři situace:
227 * *Already up-to-date* je situace, kdy už je větev, kterou chceme
228 sloučit, dosažitelná z aktuální větve (už byla sloučena v
229 minulosti). Při sloučení nedojde k žádné změně.
230 * *Fast-forward* je opak předchozí situace, tj. aktuální větev je
231 dosažitelná ze slučované větve. To odpovídá situaci, kdy
232 aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
233 na poslední commit) posunuta na novější verzi.
234 * *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
235 o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
237 Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
238 obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
240 1. Zkuste provést sloučení své větve *master* s *origin/master*
242 git merge origin/master
243 Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
245 git merge origin/master
246 Updating 0ebd30c..a99dc51
249 contrib/Makefile.am | 9 +-
251 Toto je velmi častá operace a proto lze operace `fetch` a `merge`
252 nahradit jedním příkazem
255 2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
256 založit si na to samostatnou větev. Dnešním úkolem bude sloučit
257 větev *osp/only-directories* s větví *master* a protože to není
258 triviální založte si na to novou větev:
260 git checkout -b homework
261 3. Pokud provedete sloučení
263 git merge osp/only-directories
264 Výsledek bude vypadat pravděpodobně takto:
266 Auto-merging doc/man/mc.1.in
267 Auto-merging src/filemanager/find.c
268 CONFLICT (content): Merge conflict in src/filemanager/find.c
269 Automatic merge failed; fix conflicts and then commit the result.
271 Vidíme, že se automaticky povedlo sloučit změny v souboru
272 `doc/mc.1.in`, ale při slučování změn ve `src/find.c` už takové
273 štěstí nemáme a výsledkem je konflikt.
279 Konflikt lze řešit několika způsoby (viz také `git merge --help`):
281 * Vzdáme to a vrátíme se k verzi před slučováním
285 * Konflikt vyřešíme a oznámíme to gitu příkazy `git add` a `git
286 commit` (jak nám git napovídá v hláškách)
288 V průběhu řešení konfliktu je užitečné používat příkaz `git status`,
289 abychom zjistili, co je ještě potřeba vyřešit. V našem případě vypadá
293 # Changes to be committed:
295 # modified: doc/man/mc.1.in
298 # (use "git add/rm <file>..." as appropriate to mark resolution)
300 # both modified: src/filemanager/find.c
302 Konflikt lze řešit následujícími způsoby:
304 * Soubor s konfliktem otevřeme v textovém editoru a najdeme sekvence
305 `<<<<<<<<`, `=========` a `>>>>>>>>`, kterými jsou označené
306 jednotlivé konfliktní oblasti. Tato místa musíme opravit tak, aby
307 kód dával smysl a poté zmíněné sekvence znaků smažeme.
308 * Použijeme příkaz `git mergetool`, který spouští grafický nástroj
309 (např. [kdiff3][kdiff3]), který nám se slučováním pomůže.
311 `kdiff3` vedle sebe zobrazuje 3 různé verze projektu: poslední
312 společná verze (base), verzi z větve před slučováním (local) a verzi
313 ze slučované větve (remote), tj. té uvedené jako parametr v příkazu
316 Ve spodní části obrazovky je pak vidět výsledek slučování, který
317 můžeme měnit buď přímou editací a nebo výběrem jednotlivých verzí
318 pomocí tlačítek A, B a C. V tomto okně je potřeba zbavit se všech
319 řádek, které mají v levém sloupci `?` – tj. konfliktů.
321 Při řešení konfliktů nám může pomoct i příkaz `gitk --merge`, který
322 zobrazí pouze commity, které modifikovaly konfliktní soubory.
323 Jednoduše tam můžeme zjistit, které změny konflikt způsobily.
325 Git obsahuje poměrně jednoduchý algoritmus (v porovnání s jinými
326 verzovacími systémy) pro slučování různých verzí souborů. Některým
327 studentům se to nelíbí a stěžují si. Přečtěte si
328 [názor Linuse Torvaldse][mergealg], proč tomu tak je.
330 [mergealg]:http://stackoverflow.com/questions/612580/how-does-git-solve-the-merging-problem/612747#612747
332 [kdiff3]:http://kdiff3.sourceforge.net/
337 K tomu, aby výsledky vaší práce na open source projektech byly snadno
338 dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
339 si budou moct ostatní vaše změny stáhnout.
341 1. Zaregistrujte se na [GitHubu](https://github.com/). V závislosti na
342 tom, jakým protokolem chcete k repozitářům na GitHubu přistupovat
343 si nastavte buď [password caching][passcache] (pro HTTP) nebo
344 [SSH klíče][sshkeys] (pro SSH).
346 [passcache]:https://help.github.com/articles/set-up-git#password-caching
347 [sshkeys]:https://help.github.com/articles/generating-ssh-keys
349 2. Vytvoření repozitáře na GitHubu. Můžete založit buď
350 [nový projekt][new] nebo udělat tzv. "fork" existujícího projektu.
352 Pro účely tohoto cvičení si [založte fork][forkmc]
353 [Midnight commanderu][osp-mc]. Do takto vytvořeného repozitáře pak
354 nahrajete úkol z dnešního cvičení.
356 3. Do svého repozitáře na GitHubu nahrajete větev z lokálního
357 repozitáře některým z těchto způsobů:
359 git remote add github https://github.com/<mujlogin>/mc.git
360 git push github HEAD:homework
363 git push https://github.com/<mujlogin>/mc.git homework
366 git push ssh://git@github.com/<mujlogin>/mc.git homework
368 [new]:https://github.com/new
369 [osp-mc]:https://github.com/CTU-OSP/mc
370 [forkmc]:https://github.com/CTU-OSP/mc/fork
376 Proveďte sloučení větve `ssh://git@rtime.felk.cvut.cz/osp/mc
377 only-directories` s aktuální vývojovou větví Midnight Commanderu
378 (`origin/master`). Výsledek musí jít zkompilovat a musí obsahovat
379 funkcionalitu přidanou do větve `only-directories`. Výsledek uložte do
380 [vámi vytvořeného repozitáře (forku) na GitHubu][forkmc] do větve