1 [[!meta title="Verzovací systém Git"]]
8 Naučit se pracovat verzovacím systémem [Git][git]. Konrétně nás bude
10 * Využití Gitu pro distribuovaný vývojový model, který je praktikován
11 mnoha open source projekty.
12 * Efektivní prohledávání historie projektu, které je užitečné
13 například při rozhodnování jak správně vyřešit určitý konflikt.
15 [git]:http://git-scm.com/
20 Git je velmi univerzální nástroj pro správu a synchronizaci dat
21 v souborech. Kromě verzování softwaru ho lidé používají
22 k [mnoha dalším činnostem][gitsurvey09-usedfor]. Jedna z často
23 zmiňovaných nevýhod Gitu je, že oproti jiným verzovacím systémům je
24 těžší se ho naučit a používat. Možným důvodem je to, že git nabízí
25 větší funkcionalitu než většina ostatních systémů, která se ale
26 využije jen ve speciálních případech – například jen u extrémně
27 velkých projektů jako Linuxové jádro. Ať už to tak je, nebo ne, faktem
28 je, že Git se neustále vyvíjí a mnoho úsilí je věnováno právě zlepšení
29 uživatelské přivětivosti.
31 [gitsurvey09-usedfor]:http://git.wiki.kernel.org/index.php/GitSurvey2009#07._I_use_Git_for_.28check_all_that_apply.29:
33 Pro pochopení Gitu je důležité mít základní představu o tom, jak Git
34 pracuje s větvemi, jak bylo popsáno v [[přednášce|prednasky/intro-to-git.pdf]]
35 na slidech "*Working on branches*" a "*Working with remotes*".
37 V tomto cvičení budeme opět pracovat s projektem
38 [Midnight commander][mc] z [[1. cvičení|1]]. Pokud s gitem začínáte,
39 doporučuji v průběhu jednotlivých kroků kontrolovat stav repozitáře
40 pomocí grafických nástrojů.
42 * Příkaz `gitk` zobrazuje graficky historii a dovoluje její
43 interaktivní procházení. Přijímá stejné volby jako `git log`, takže
44 v příkazech níže ho můžete použít i pro vizualizaci výstupu `git
47 * Příkaz `git gui` je grafický nástroj částečně nahrazující příkazy
48 `git status` a `git commit`. Pomocí menu je možné provádět i další
49 operace jako např. vytváření větví a práce se vzdálenými repozitáři.
51 * Dále existuje ještě spousta dalších [nástrojů][tools]. Já osobně používám
52 kromě výše zmíněných příkazů ještě `tig` a `qgit`.
54 Dále se vám určitě bude hodit dokumentace:
59 [tools]:http://git-scm.com/tools
64 1. Základní nastavení. Aby vaše commity obsahovaly správné údaje o
65 vás, nastavte si jméno a email:
67 git config --global user.name "Your Name Comes Here"
68 git config --global user.email you@yourdomain.example.com
72 1. Předpokládáme, že máte zdrojové kódy midnight commanderu někde na
73 disku, takže se přesuňte do adresáře s nimi.
80 2. Možná budete chtít zachovat vaší práci z prvního cvičení. Uložíme
81 jí do nové větve *cviceni1*. Nejprve se ale podíváme v jakém stavu
88 # Changed but not updated:
89 # (use "git add <file>..." to update what will be committed)
90 # (use "git checkout -- <file>..." to discard changes in working directory)
93 # modified: po/be-tarask.po
96 # modified: src/cmddef.h
97 # modified: src/main.c
98 Vidíme, že pracujeme na větvi *master* a vzhledem k verzi uložené v
99 repozitáři máme několik změněných souborů.
101 [mc]:http://www.midnight-commander.org/
103 1. Midnight commander má bohužel jednu vlastnost, která může ztížit
104 vaše začátky s gitem. Při kompilaci dojde k automatickému
105 přegenerování některých souborů v repozitáři a git potom hlásí, že
106 jsme tyto soubory změnili a "otravuje" s nimi při každém commitu.
108 Naštěstí existuje možnost jak gitu říct, že nás změny v některých
109 souborech nezajímají:
111 git update-index --assume-unchanged $(git ls-files po m4)
113 Příkaz `git ls-files po m4` vypíše všechny soubory z adresářů *po*
114 a *m4*, které jsou spravované gitem a příkazem `git update-index
115 --assume-unchanged` pak gitu sdělíme, aby si do indexu poznamenal,
116 že tyto soubory má ignorovat.
118 > *Poznámka:* Možná víte o souborech *.gitignore* (viz `man
119 > gitignore`), které slouží k podobnému účelu. Ostatně midnight
120 > commander je také využívá, jak se můžete snadno přesvědčit:
124 > Soubory *.gitignore* se ale vztahují pouze na soubory, které
125 > ještě nejsou součástí repozitáře, což není případ výše zmíněných
128 3. Vytvoříme větev *cviceni1* a přepneme se na ni:
130 git checkout -b cviceni1
132 Nyní už by měl `git status` ukazovat že pracujeme s větví
133 *cviceni1* a vidíme pouze námi modifikované soubory.
135 4. Nyní provedeme *commit*:
137 git commit -a -m 'Zmeny z prvniho cviceni'
139 Parametrem `-a` říkáme, že "commitujeme" vše (all) a `-m` udává
140 komentář ke commitu (message). Kdybychom `-m` vynechali, git spustí
141 editor a nechá nás napsat zprávu v něm.
143 > *Poznámka:* Pokud vám nevyhovuje výchozí editor (většinou `vi`),
144 > nastavte si, že chcete používat jiný editor (např. `pico`):
146 > git config --global core.editor pico
148 5. Nyní se přepneme zpět na větev *master*:
151 V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
153 6. Seznam větví v našem repozitáři zjistíme příkazem
156 Aktuální větev je označena hvězdičkou `*`.
158 Práce s více vzdálenými repozitáři
159 ----------------------------------
161 Do teď jsme pracovali pouze s jedním vzdáleným repozitářem. Mezi velké
162 výhody gitu (a ostatních distribuovaných verzovacích systémů) patří
163 schopnost pracovat s více vzdálenými repozitáři.
165 1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
169 Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
172 1. Pokud chceme nějaký [konkrétní vzdálený repozitář][w/osp.git] používat často,
173 vyplatí se ho pojmenovat krátkým jménem (v příkladu níže *osp*),
174 abychom nemuseli pořád psát dlouhé URL:
176 git remote add osp git://repo.or.cz/midnight-commander/osp.git
178 2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
181 3. Příkaz nám vypíše, že v repozitáři byly dvě 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 vzdálená větev má prefix `<remote>/`.
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ů
196 git log -p osp/only-directories ^master
197 gitk osp/only-directories ^master
199 6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
200 je výchozí a proto ho nemusíme zadávat:
203 Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
205 git log master..origin/master
207 Slučování větví (merge)
208 -----------------------
210 Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
211 můžou při slučování nastat tři situace:
213 * *Already up-to-date* je situace, kdy už je větev, kterou chceme
214 sloučit, dosažitelná z aktuální větve (už byla sloučena v
215 minulosti). Při sloučení nedojde k žádné změně.
216 * *Fast-forward* je opak předchozí situace, tj. aktuální větev je
217 dosažitelná ze slučované větve. To odpovídá situaci, kdy
218 aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
219 na poslední commit) posunuta na novější verzi.
220 * *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
221 o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
223 Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
224 obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
226 1. Zkuste provést sloučení vaší větve *master* s *origin/master*
228 git merge origin/master
229 Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
231 git merge origin/master
232 Updating 0ebd30c..a99dc51
235 contrib/Makefile.am | 9 +-
237 Toto je velmi častá operace a proto lze oprace `fetch` a `merge`
238 nahradit jedním příkazem
241 2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
242 založit si na to samostatnou větev. Dnešním úkolem bude sloučit
243 větev *osp/only-directories* s větví *master* a protože to není
244 triviální založte si na to novou větev:
246 git checkout -b homework
247 3. Pokud provedete sloučení
249 git merge osp/only-directories
250 Výsledek bude vypadat pravděpodobně takto:
252 Renaming doc/mc.1.in => doc/man/mc.1.in
253 Auto-merging doc/man/mc.1.in
254 Auto-merging src/find.c
255 CONFLICT (content): Merge conflict in src/find.c
256 Automatic merge failed; fix conflicts and then commit the result.
257 Vidíme, že git správně zjistil, že soubor `doc/mc.1.in` byl
258 v novější verzi přejmenován a provedl sloučení až po přejmenování.
259 Při slučování změn ve `src/find.c` už takové štěstí nemáme a
260 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á
277 výstup zhruba takhle:
279 # On branch merge-assignment
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/find.c
290 Konflikt lze řešit následujícími způsoby:
292 * V textovém editoru najdeme sekvence `<<<<<<<<`, `=========` a
293 `>>>>>>>>`, kterými jsou označené jednotlivé konfliktní oblasti.
294 Tato místa musíme opravit tak, aby dávala smysl a poté zmíněné
295 sekvence znaků smažeme.
296 * `git mergetool` je nástroj, který spouští grafický nástroj (např.
297 [kdiff3][kdiff3]), který vám se slučováním pomůže.
300 sebe zobrazuje 3 různé verze projektu: poslední společná verze
301 (base), verzi z větve před slučováním (local) a verzi ze slučované
302 větve (remote) tj. té uvedené jako parametr v příkazu `git merge`.
304 Ve spodní části obrazovky je pak vidět výsledek slučování, který
305 můžeme měnit buď přímou editací a nebo výběrem jednotlivých verzí
306 pomocí tlačítek A, B a C. V tomto okně je potřeba zbavit se všech
307 řadek, které maji v levém sloupci `?` - tj. konfliktů.
308 * `gitk --merge` - zobrazí pouze commity, které modifikovaly
310 [kdiff3]:http://kdiff3.sourceforge.net/
311 Repozitář na repo.or.cz
312 ---------------------------
314 K tomu, aby výsledky vaší práce na open source projektech byly snadno
315 dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
316 si budou moct ostatní vaše změny stáhnout.
318 1. [Zaregistrujte][reg] se na [repo.or.cz][roc]. K repozitáři na
319 repo.or.cz se přistupuje protokolem SSH a autorizace se provádí na
320 základě veřejných klíčů.
322 1. Pokud žádný klíč nemáte, vytvořte si ho příkazem
326 Příkaz se vás zeptá kam klíč uložit. Výchozí volba vám zpočátku
327 bude stačit. Dále se zeptá na heslo (passphrase) k vašemu
328 privátnímu klíči. Pokud žádné heslo nezadáte, bude se moct
329 kdokoli, kdo se dostane k souboru s vaším klíčem (např.
330 administrátor školních serverů), autorizovat jako vy.
332 2. Pokud jste se rozhodli chránit klíč heslem, je otravné zadávat
333 heslo vždy, když klíč používáte. Naštěstí existuje program
334 `ssh-agent`, který uchovává odheslované klíče v paměti a
335 poskytuje je vždy, když je nějaký oprávněný program potřebuje.
336 Vy tak zadáte heslo jen jednou a to když předáváte klíč
337 ssh-agentovi příkazem
341 [reg]:http://repo.or.cz/reguser.cgi
342 [roc]:http://repo.or.cz/
344 2. Vytvoření repozitáře na repo.or.cz.
346 Můžete založit buď [nový projekt][new] a nebo udělat tzv.
347 [fork existujícího projektu][forkmc]. Pro oba typy projektů můžete
348 zvolit zda bude repozitář pouze automaticky aktualizovanou kopií
349 jiného repozitáře (*mirror*) a nebo zda-li bude možné do něj přímo
350 ukládat nové commity (*push*).
352 Pro účely tohoto cvičení si
353 [založte fork][forkmc] [Midnight commanderu][w/osp.git] v *Push módu*, který se
354 bude jmenovat podle vašeho loginu. Do tohoto repozitáře pak
355 nahrajete úkol z dnešního cvičení.
357 3. Do vašeho vzdáleného repozitáře můžete nahrát vaší větev některým z
360 git push ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git homework
363 git remote add repo-or-cz ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git
364 git push repo-or-cz homework
366 [new]:http://repo.or.cz/regproj.cgi
367 [forkmc]:http://repo.or.cz/regproj.cgi?fork=midnight-commander/osp.git
372 Proveďte sloučení větve `git://repo.or.cz/midnight-commander/osp.git
373 only-directories` s aktuální vývojovou větví (`master`). Výsledek
374 uložte do [vámi vytvořeného repozitáře (forku) na repo.or.cz][forkmc]
377 [w/osp.git]:http://repo.or.cz/w/midnight-commander/osp.git