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