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