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