]> 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*.
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 Doposud 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>/` (v našem
184    případě `origin/` nebo `osp/`).
185
186 4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
187
188        git log osp/only-directories ^master
189            git log master..osp/only-directories
190    Tyto dva příkazy jsou ekvivalentní a vypisují commity, které jsou
191    ve větvi *osp/only-directories* a zároveň nejsou (^) ve větvi *master*.
192    
193    Chcete-li vidět i změny v kódu použijte jeden z následujících příkazů:
194
195        git log -p osp/only-directories ^master
196            gitk osp/only-directories ^master
197
198 6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
199    je výchozí a proto ho nemusíme zadávat:
200
201        git fetch
202    Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
203    
204        git log master..origin/master
205
206 Slučování větví (merge)    
207 -----------------------
208
209 Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
210 Můžou při slučování nastat tři situace:
211
212 * *Already up-to-date* je situace, kdy už je větev, kterou chceme
213   sloučit, dosažitelná z aktuální větve (už byla sloučena v
214   minulosti). Při sloučení nedojde k žádné změně.
215 * *Fast-forward* je opak předchozí situace, tj. aktuální větev je
216   dosažitelná ze slučované větve. To odpovídá situaci, kdy
217   aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
218   na poslední commit) posunuta na novější verzi.
219 * *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
220   o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
221   
222 Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
223 obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
224
225 1. Zkuste provést sloučení své větve *master* s *origin/master*
226
227        git merge origin/master
228    Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
229
230        git merge origin/master
231        Updating 0ebd30c..a99dc51
232        Fast forward
233         configure.ac                  |    1 +
234         contrib/Makefile.am           |    9 +-
235         ...
236    Toto je velmi častá operace a proto lze operace `fetch` a `merge`
237    nahradit jedním příkazem
238
239        git pull
240 2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
241    založit si na to samostatnou větev. Dnešním úkolem bude sloučit
242    větev *osp/only-directories* s větví *master* a protože to není
243    triviální založte si na to novou větev:
244    
245        git checkout -b homework
246 3. Pokud provedete sloučení
247
248        git merge osp/only-directories
249    Výsledek bude vypadat pravděpodobně takto:
250
251        Auto-merging doc/man/mc.1.in
252            Auto-merging src/filemanager/find.c
253            CONFLICT (content): Merge conflict in src/filemanager/find.c
254            Automatic merge failed; fix conflicts and then commit the result. 
255
256    Vidíme, že se automaticky povedlo sloučit změny v souboru
257    `doc/mc.1.in`, ale při slučování změn ve `src/find.c` už takové
258    štěstí nemáme a výsledkem je konflikt.
259         
260
261 Řešení konfliktů
262 ----------------
263
264 Konflikt lze řešit několika způsoby (viz také `git merge --help`):
265
266 * Vzdáme to a vrátíme se k verzi před slučováním
267
268        git reset --hard
269         
270 * Konflikt vyřešíme a oznámíme to gitu příkazy `git add` a `git
271   commit` (jak nám git napovídá v hláškách)
272
273 V průběhu řešení konfliktu je užitečné používat příkaz `git status`,
274 Abychom zjistili, co je ještě potřeba vyřešit. V našem případě vypadá
275 výstup zhruba takto:
276    
277     # On branch homework
278     # Changes to be committed:
279     #
280     #   modified:   doc/man/mc.1.in
281     #
282     # Unmerged paths:
283     #   (use "git add/rm <file>..." as appropriate to mark resolution)
284     #
285     #   both modified:      src/filemanager/find.c
286
287 Konflikt lze řešit následujícími způsoby:
288
289 * Soubor s konfliktem otevřeme v textovém editoru a najdeme sekvence
290   `<<<<<<<<`, `=========` a `>>>>>>>>`, kterými jsou označené
291   jednotlivé konfliktní oblasti. Tato místa musíme opravit tak, aby
292   kód dával smysl a poté zmíněné sekvence znaků smažeme.
293 * Použijeme příkaz `git mergetool`, který spouští grafický nástroj
294   (např. [kdiff3][kdiff3]), který nám se slučováním pomůže.
295   
296   `kdiff3` vedle sebe zobrazuje 3 různé verze projektu: poslední
297   společná verze (base), verzi z větve před slučováním (local) a verzi
298   ze slučované větve (remote), tj. té uvedené jako parametr v příkazu
299   `git merge`.
300   
301   Ve spodní části obrazovky je pak vidět výsledek slučování, který
302   můžeme měnit buď přímou editací a nebo výběrem jednotlivých verzí
303   pomocí tlačítek A, B a C. V tomto okně je potřeba zbavit se všech
304   řádek, které mají v levém sloupci `?` – tj. konfliktů.
305
306 Při řešení konfliktů nám může pomoct i příkaz `gitk --merge`, který
307 zobrazí pouze commity, které modifikovaly konfliktní soubory.
308 Jednoduše tam můžeme zjistit, které změny konflikt způsobily.
309
310 [kdiff3]:http://kdiff3.sourceforge.net/
311
312 Repozitář na GitHubu
313 --------------------
314
315 K tomu, aby výsledky vaší práce na open source projektech byly snadno
316 dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
317 si budou moct ostatní vaše změny stáhnout.
318
319 1. Zaregistrujte se na [GitHubu](https://github.com/). V závislosti na
320    tom, jakým protokolem chcete k repozitářům na GitHubu přistupovat
321    si nastavte buď [password caching][passcache] (pro HTTP) nebo
322    [SSH klíče][sshkeys] (pro SSH).
323
324 [passcache]:https://help.github.com/articles/set-up-git#password-caching   
325 [sshkeys]:https://help.github.com/articles/generating-ssh-keys
326
327 2. Vytvoření repozitáře na GitHubu. Můžete založit buď
328    [nový projekt][new] nebo udělat tzv. "fork" existujícího projektu.
329    
330    Pro účely tohoto cvičení si [založte fork][forkmc]
331    [Midnight commanderu][osp-mc]. Do takto vytvořeného repozitáře pak
332    nahrajete úkol z dnešního cvičení.
333    
334 3. Do svého repozitáře na GitHubu nahrajete větev z lokálního
335    repozitáře některým z těchto způsobů:
336
337        git push https://github.com/<mujlogin>/mc.git homework
338    nebo
339
340        git push ssh://git@github.com/<mujlogin>/mc.git homework
341    nebo
342
343        git remote add github https://github.com/<mujlogin>/mc.git
344        git push github homework
345
346 [new]:https://github.com/new
347 [osp-mc]:https://github.com/CTU-OSP/mc
348 [forkmc]:https://github.com/CTU-OSP/mc/fork
349
350 Zadání
351 ======
352
353 Proveďte sloučení větve `ssh://git@rtime.felk.cvut.cz/osp/mc
354 only-directories` s aktuální vývojovou větví Midnight Commanderu
355 (`origin/master`). Výsledek musí jít zkompilovat a musí obsahovat
356 funkcionalitu přidanou do větve `only-directories`. Výsledek uložte do
357 [vámi vytvořeného repozitáře (forku) na GitHubu][forkmc] do větve
358 `homework`.