]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/4.mdwn
(no commit message)
[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 * 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.
14
15 [git]:http://git-scm.com/
16
17 Úvod
18 ====
19
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.
30
31 [gitsurvey09-usedfor]:http://git.wiki.kernel.org/index.php/GitSurvey2009#07._I_use_Git_for_.28check_all_that_apply.29:
32
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*".
36
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ů.
41
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
45   log`.
46
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.
50
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`.
53   
54 Dále se vám určitě bude hodit dokumentace:
55
56     git help <příkaz>
57     git <příkaz> --help
58   
59 [tools]:http://git-scm.com/tools
60
61 Postup
62 ======
63
64 1. Základní nastavení. Aby vaše commity obsahovaly správné údaje o
65    vás, nastavte si jméno a email:
66
67         git config --global user.name "Your Name Comes Here"
68         git config --global user.email you@yourdomain.example.com
69
70
71
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.
74    
75         cd ~/mc
76
77 Lokální větve
78 -------------
79
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
82    máme zdrojové kódy:
83
84         git status
85    Dostaneme něco jako:
86    
87         # On branch master
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)
91         #
92         #       modified:   po/az.po
93         #       modified:   po/be-tarask.po
94         #       modified:   po/be.po
95         #       ...
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ů.
100
101 [mc]:http://www.midnight-commander.org/
102
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.
107    
108    Naštěstí existuje možnost jak gitu říct, že nás změny v některých
109    souborech nezajímají: 
110    
111         git update-index --assume-unchanged $(git ls-files po m4)
112
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.
117    
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:
121    >
122    >     cat .gitignore
123    >
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
126    > souborů.
127
128 3. Vytvoříme větev *cviceni1* a přepneme se na ni:
129
130         git checkout -b cviceni1
131
132    Nyní už by měl `git status` ukazovat že pracujeme s větví
133    *cviceni1* a vidíme pouze námi modifikované soubory.
134
135 4. Nyní provedeme *commit*:
136
137         git commit -a -m 'Zmeny z prvniho cviceni'
138         
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.   
142
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`):
145    > 
146    >      git config --global core.editor pico
147
148 5. Nyní se přepneme zpět na větev *master*:
149
150         git checkout master
151    V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
152
153 6. Seznam větví v našem repozitáři zjistíme příkazem
154
155         git branch
156    Aktuální větev je označena hvězdičkou `*`.
157    
158 Práce s více vzdálenými repozitáři
159 ----------------------------------
160
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.
164
165 1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
166    
167         git remote -v
168
169    Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
170    URL.
171
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:
175    
176         git remote add osp git://repo.or.cz/midnight-commander/osp.git
177         
178 2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
179
180         git fetch osp
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
183    
184         git branch -r
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>/`.
187
188 4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
189
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*.
194    
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
198
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:
201
202         git fetch
203    Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
204    
205         git log master..origin/master
206
207 Slučování větví (merge)    
208 -----------------------
209
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:
212
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í.
222   
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ě.
225
226 1. Zkuste provést sloučení vaší větve *master* s *origin/master*
227
228         git merge origin/master
229    Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
230
231         git merge origin/master
232         Updating 0ebd30c..a99dc51
233         Fast forward
234          configure.ac                  |    1 +
235          contrib/Makefile.am           |    9 +-
236          ...
237    Toto je velmi častá operace a proto lze oprace `fetch` a `merge`
238    nahradit jedním příkazem
239
240         git pull
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:
245    
246         git checkout -b homework
247 3. Pokud provedete sloučení
248
249         git merge osp/only-directories
250    Výsledek bude vypadat pravděpodobně takto:
251
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.
261         
262
263 Řešení konfliktů
264 ----------------
265
266 Konflikt lze řešit několika způsoby (viz také `git merge --help`):
267
268 * Vzdáme to a vrátíme se k verzi před slučováním
269
270         git reset --hard
271         
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)
274
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:
278    
279     # On branch merge-assignment
280     # Changes to be committed:
281     #
282     #   modified:   doc/man/mc.1.in
283     #
284     # Unmerged paths:
285     #   (use "git add/rm <file>..." as appropriate to mark resolution)
286     #
287     #   both modified:      src/find.c
288     #
289
290 Konflikt lze řešit následujícími způsoby:
291
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. 
298   
299   `kdiff3` vedle
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`.
303   
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
309   konfliktní soubory.
310 [kdiff3]:http://kdiff3.sourceforge.net/
311 Repozitář na repo.or.cz
312 ---------------------------
313
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.
317
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íčů.
321    
322    1. Pokud žádný klíč nemáte, vytvořte si ho příkazem 
323    
324             ssh-keygen
325
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.
331    
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
338
339             ssh-add
340
341 [reg]:http://repo.or.cz/reguser.cgi
342 [roc]:http://repo.or.cz/
343
344 2. Vytvoření repozitáře na repo.or.cz.
345
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*).
351    
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í.
356    
357 3. Do vašeho vzdáleného repozitáře můžete nahrát vaší větev některým z
358    těchto způsobů
359
360         git push ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git homework
361    nebo 
362
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
365
366 [new]:http://repo.or.cz/regproj.cgi
367 [forkmc]:http://repo.or.cz/regproj.cgi?fork=midnight-commander/osp.git
368
369 Zadání
370 ======
371
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` z prvního cvičení). Výsledek
374 uložte do [vámi vytvořeného repozitáře (forku) na repo.or.cz][forkmc]
375 do větve `homework`.
376
377 [w/osp.git]:http://repo.or.cz/w/midnight-commander/osp.git