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