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.
17 [git]:http://git-scm.com/
22 Git je velmi univerzální nástroj pro správu a synchronizaci dat
23 v souborech. Kromě verzování softwaru ho lidé používají
24 k [mnoha dalším činnostem][gitsurvey-usedfor]. Jedna z často
25 zmiňovaných nevýhod Gitu je, že oproti jiným verzovacím systémům je
26 těžší se ho naučit a používat. Možným důvodem je to, že git nabízí
27 větší funkcionalitu než většina ostatních systémů, která se ale
28 využije jen ve speciálních případech – například jen u extrémně
29 velkých projektů jako Linuxové jádro. Ať už to tak je, nebo ne, faktem
30 je, že Git se neustále vyvíjí a mnoho úsilí je věnováno právě zlepšení
31 uživatelské přivětivosti.
33 [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
35 Pro pochopení Gitu je důležité mít základní představu o tom, jak Git
36 pracuje s větvemi, což bylo popsáno v [[přednášce|prednasky/intro-to-git.pdf]]
37 na slidech "*Working on branches*" a "*Working with remotes*".
39 V tomto cvičení budeme opět pracovat s projektem
40 [Midnight commander][mc] z [[1. cvičení|1]]. Pokud s gitem začínáte,
41 doporučuji v průběhu jednotlivých kroků kontrolovat stav repozitáře
42 pomocí grafických nástrojů:
44 * Příkaz `gitk` zobrazuje graficky historii a dovoluje její
45 interaktivní procházení. Přijímá stejné volby jako `git log`, takže
46 v příkazech níže ho můžete použít i pro "vizualizaci" výstupu `git
49 * Příkaz `git gui` je grafický nástroj částečně nahrazující příkazy
50 `git status` a `git commit`. Pomocí menu je možné provádět i další
51 operace jako např. vytváření větví a práce se vzdálenými repozitáři.
53 * Dále existuje ještě spousta dalších [nástrojů][tools]. Já osobně používám
54 kromě výše zmíněných příkazů ještě `tig` a `qgit`.
56 Dále se vám určitě bude hodit dokumentace:
61 [tools]:http://git-scm.com/docs/git-tools
66 1. Základní nastavení. Aby vaše commity obsahovaly správné údaje o
67 vás, nastavte si jméno a email:
69 git config --global user.name "Your Name Comes Here"
70 git config --global user.email you@yourdomain.example.com
74 1. Předpokládáme, že máte zdrojové kódy midnight commanderu někde na
75 disku, takže se přesuňte do adresáře s nimi.
82 2. Možná budete chtít zachovat vaší práci z prvního cvičení. Uložíme
83 jí do nové větve *cviceni1*. Nejprve se ale podíváme v jakém stavu
90 # Changes not staged for commit:
91 # (use "git add <file>..." to update what will be committed)
92 # (use "git checkout -- <file>..." to discard changes in working directory)
94 # modified: lib/keybind.h
95 # modified: src/filemanager/midnight.c
98 # (use "git add <file>..." to include in what will be committed)
102 no changes added to commit (use "git add" and/or "git commit -a")
103 Vidíme, že pracujeme na větvi *master* a vzhledem k verzi uložené v
104 repozitáři máme několik změněných souborů.
106 [mc]:http://www.midnight-commander.org/
108 3. Vytvoříme větev *cviceni1* a přepneme se na ni:
110 git checkout -b cviceni1
112 Nyní už by měl `git status` ukazovat že pracujeme s větví
115 4. Nyní provedeme *commit*:
117 git commit -a -m 'Zmeny z prvniho cviceni'
119 Parametrem `-a` říkáme, že "commitujeme" vše (all) a `-m` udává
120 komentář ke commitu (message). Kdybychom `-m` vynechali, git spustí
121 editor a nechá nás napsat zprávu v něm.
123 > *Poznámka:* Pokud vám nevyhovuje výchozí editor (většinou `vi`),
124 > nastavte si, že chcete používat jiný editor (např. `pico`):
126 > git config --global core.editor pico
128 5. Nyní se přepneme zpět na větev *master*:
131 V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
133 6. Seznam větví v našem repozitáři zjistíme příkazem
136 Aktuální větev je označena hvězdičkou `*`.
138 Práce s více vzdálenými repozitáři
139 ----------------------------------
141 Doposud jsme pracovali pouze s jedním vzdáleným repozitářem. Mezi velké
142 výhody gitu (a ostatních distribuovaných verzovacích systémů) patří
143 schopnost pracovat s více vzdálenými repozitáři.
145 1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
149 Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
152 1. Pokud chceme nějaký vzdálený repozitář používat často,
153 vyplatí se ho pojmenovat krátkým jménem (v příkladu níže *osp*),
154 abychom nemuseli pořád psát dlouhé URL:
156 git remote add osp ssh://git@rtime.felk.cvut.cz/osp/mc
158 V tomto repozitáři je uloženo zadání dnešní úlohy. Abyste se k němu
159 dostali, musí server znát váš veřejný SSH klíč. Jak toho docílit
160 najdete na [[samostatné stránce|rtime-git-ssh-key]]. Přístup k
161 repozitářům na serveru rtime budete potřebovat i v písemce. **Proto
162 vám důrazně doporučujeme zprovoznit přístup už na tomto cvičení,
163 abyste při písemce neztráceli čas.**
165 2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
168 V případě úspěchu bude výstup vypadat následovně:
170 remote: Counting objects: 17, done.
171 remote: Compressing objects: 100% (9/9), done.
172 remote: Total 10 (delta 4), reused 7 (delta 1)
173 Unpacking objects: 100% (10/10), done.
174 From ssh://rtime.felk.cvut.cz/osp/mc
175 * [new branch] master -> osp/master
176 * [new branch] only-directories -> osp/only-directories
178 3. Příkaz nám vypíše, že v repozitáři byly dvě nové větve. Všechny
179 větve ze vzdálených repozitářů vypíšeme příkazem
182 Zjednodušeně řečeno, jediný rozdíl mezi lokální a vzdálenou větví
183 je v tom, že jméno vzdálené větve má prefix `<remote>/` (v našem
184 případě `origin/` nebo `osp/`).
186 4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
188 git log osp/only-directories ^master
189 git log master..osp/only-directories
190 Tyto dva příkazy jsou ekvivalentní a vypisují commity, které jsou
191 ve větvi *osp/only-directories* a zároveň nejsou (^) ve větvi *master*.
193 Chcete-li vidět i změny v kódu použijte jeden z následujících příkazů:
195 git log -p osp/only-directories ^master
196 gitk osp/only-directories ^master
198 6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
199 je výchozí a proto ho nemusíme zadávat:
202 Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
204 git log master..origin/master
206 Slučování větví (merge)
207 -----------------------
209 Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
210 Můžou při slučování nastat tři situace:
212 * *Already up-to-date* je situace, kdy už je větev, kterou chceme
213 sloučit, dosažitelná z aktuální větve (už byla sloučena v
214 minulosti). Při sloučení nedojde k žádné změně.
215 * *Fast-forward* je opak předchozí situace, tj. aktuální větev je
216 dosažitelná ze slučované větve. To odpovídá situaci, kdy
217 aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
218 na poslední commit) posunuta na novější verzi.
219 * *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
220 o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
222 Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
223 obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
225 1. Zkuste provést sloučení své větve *master* s *origin/master*
227 git merge origin/master
228 Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
230 git merge origin/master
231 Updating 0ebd30c..a99dc51
234 contrib/Makefile.am | 9 +-
236 Toto je velmi častá operace a proto lze operace `fetch` a `merge`
237 nahradit jedním příkazem
240 2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
241 založit si na to samostatnou větev. Dnešním úkolem bude sloučit
242 větev *osp/only-directories* s větví *master* a protože to není
243 triviální založte si na to novou větev:
245 git checkout -b homework
246 3. Pokud provedete sloučení
248 git merge osp/only-directories
249 Výsledek bude vypadat pravděpodobně takto:
251 Auto-merging doc/man/mc.1.in
252 Auto-merging src/filemanager/find.c
253 CONFLICT (content): Merge conflict in src/filemanager/find.c
254 Automatic merge failed; fix conflicts and then commit the result.
256 Vidíme, že se automaticky povedlo sloučit změny v souboru
257 `doc/mc.1.in`, ale při slučování změn ve `src/find.c` už takové
258 štěstí nemáme a výsledkem je konflikt.
264 Konflikt lze řešit několika způsoby (viz také `git merge --help`):
266 * Vzdáme to a vrátíme se k verzi před slučováním
270 * Konflikt vyřešíme a oznámíme to gitu příkazy `git add` a `git
271 commit` (jak nám git napovídá v hláškách)
273 V průběhu řešení konfliktu je užitečné používat příkaz `git status`,
274 Abychom zjistili, co je ještě potřeba vyřešit. V našem případě vypadá
278 # Changes to be committed:
280 # modified: doc/man/mc.1.in
283 # (use "git add/rm <file>..." as appropriate to mark resolution)
285 # both modified: src/filemanager/find.c
287 Konflikt lze řešit následujícími způsoby:
289 * Soubor s konfliktem otevřeme v textovém editoru a najdeme sekvence
290 `<<<<<<<<`, `=========` a `>>>>>>>>`, kterými jsou označené
291 jednotlivé konfliktní oblasti. Tato místa musíme opravit tak, aby
292 kód dával smysl a poté zmíněné sekvence znaků smažeme.
293 * Použijeme příkaz `git mergetool`, který spouští grafický nástroj
294 (např. [kdiff3][kdiff3]), který nám se slučováním pomůže.
296 `kdiff3` vedle sebe zobrazuje 3 různé verze projektu: poslední
297 společná verze (base), verzi z větve před slučováním (local) a verzi
298 ze slučované větve (remote), tj. té uvedené jako parametr v příkazu
301 Ve spodní části obrazovky je pak vidět výsledek slučování, který
302 můžeme měnit buď přímou editací a nebo výběrem jednotlivých verzí
303 pomocí tlačítek A, B a C. V tomto okně je potřeba zbavit se všech
304 řádek, které mají v levém sloupci `?` – tj. konfliktů.
306 Při řešení konfliktů nám může pomoct i příkaz `gitk --merge`, který
307 zobrazí pouze commity, které modifikovaly konfliktní soubory.
308 Jednoduše tam můžeme zjistit, které změny konflikt způsobily.
310 [kdiff3]:http://kdiff3.sourceforge.net/
315 K tomu, aby výsledky vaší práce na open source projektech byly snadno
316 dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
317 si budou moct ostatní vaše změny stáhnout.
319 1. Zaregistrujte se na [GitHubu](https://github.com/). V závislosti na
320 tom, jakým protokolem chcete k repozitářům na GitHubu přistupovat
321 si nastavte buď [password caching][passcache] (pro HTTP) nebo
322 [SSH klíče][sshkeys] (pro SSH).
324 [passcache]:https://help.github.com/articles/set-up-git#password-caching
325 [sshkeys]:https://help.github.com/articles/generating-ssh-keys
327 2. Vytvoření repozitáře na GitHubu. Můžete založit buď
328 [nový projekt][new] nebo udělat tzv. "fork" existujícího projektu.
330 Pro účely tohoto cvičení si [založte fork][forkmc]
331 [Midnight commanderu][osp-mc]. Do takto vytvořeného repozitáře pak
332 nahrajete úkol z dnešního cvičení.
334 3. Do svého repozitáře na GitHubu nahrajete větev z lokálního
335 repozitáře některým z těchto způsobů:
337 git push https://github.com/<mujlogin>/mc.git homework
340 git push ssh://git@github.com/<mujlogin>/mc.git homework
343 git remote add github https://github.com/<mujlogin>/mc.git
344 git push github homework
346 [new]:https://github.com/new
347 [osp-mc]:https://github.com/CTU-OSP/mc
348 [forkmc]:https://github.com/CTU-OSP/mc/fork
353 Proveďte sloučení větve `ssh://git@rtime.felk.cvut.cz/osp/mc
354 only-directories` s aktuální vývojovou větví Midnight Commanderu
355 (`origin/master`). Výsledek musí jít zkompilovat a musí obsahovat
356 funkcionalitu přidanou do větve `only-directories`. Výsledek uložte do
357 [vámi vytvořeného repozitáře (forku) na GitHubu][forkmc] do větve