]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/4.mdwn
Do not mention `git update-index --assume-unchanged`
[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            # Changed but not updated:
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:       po/az.po
95            #    modified:       po/be-tarask.po
96            #    modified:       po/be.po
97            #       ...
98            #    modified:       src/cmddef.h
99            #    modified:       src/main.c
100    Vidíme, že pracujeme na větvi *master* a vzhledem k verzi uložené v
101    repozitáři máme několik změněných souborů.
102
103 [mc]:http://www.midnight-commander.org/
104
105 3. Vytvoříme větev *cviceni1* a přepneme se na ni:
106
107        git checkout -b cviceni1
108
109    Nyní už by měl `git status` ukazovat že pracujeme s větví
110    *cviceni1* a vidíme pouze námi modifikované soubory.
111
112 4. Nyní provedeme *commit*:
113
114        git commit -a -m 'Zmeny z prvniho cviceni'
115         
116    Parametrem `-a` říkáme, že "commitujeme" vše (all) a `-m` udává
117    komentář ke commitu (message). Kdybychom `-m` vynechali, git spustí
118    editor a nechá nás napsat zprávu v něm.   
119
120    > *Poznámka:* Pokud vám nevyhovuje výchozí editor (většinou `vi`),
121    > nastavte si, že chcete používat jiný editor (např. `pico`):
122    > 
123    >     git config --global core.editor pico
124
125 5. Nyní se přepneme zpět na větev *master*:
126
127        git checkout master
128    V adresáři se vám teď objeví verze bez vašich úprav z 1. cvičení.
129
130 6. Seznam větví v našem repozitáři zjistíme příkazem
131
132        git branch
133    Aktuální větev je označena hvězdičkou `*`.
134    
135 Práce s více vzdálenými repozitáři
136 ----------------------------------
137
138 Do teď jsme pracovali pouze s jedním vzdáleným repozitářem. Mezi velké
139 výhody gitu (a ostatních distribuovaných verzovacích systémů) patří
140 schopnost pracovat s více vzdálenými repozitáři.
141
142 1. Které vzdálené repozitáře máme nakonfigurované zjistíme pomocí
143    
144        git remote -v
145
146    Vidíme, že máme nakonfigurovaný repozitář s názvem *origin* a jeho
147    URL.
148
149 1. Pokud chceme nějaký vzdálený repozitář používat často,
150    vyplatí se ho pojmenovat krátkým jménem (v příkladu níže *osp*),
151    abychom nemuseli pořád psát dlouhé URL:
152    
153        git remote add osp ssh://git@rtime.felk.cvut.cz/osp/mc
154
155    V tomto repozitáři je uloženo zadání dnešní úlohy. Abyste se k němu
156    dostali, musí server znát váš veřejný SSH klíč. Jak toho docílit
157    najdete na [[samostatné stránce|rtime-git-ssh-key]]. Přístup k
158    repozitářům na serveru rtime budete potřebovat i v písemce. **Proto
159    vám důrazně doporučujeme zprovoznit přístup už na tomto cvičení,
160    abyste při písemce neztráceli čas.**
161         
162 2. Nyní můžeme stáhnout obsah právě přidaného repozitáře:
163
164        git fetch osp
165    V případě úspěchu bude výstup vypadat následovně:
166
167        remote: Counting objects: 17, done.
168            remote: Compressing objects: 100% (9/9), done.
169            remote: Total 10 (delta 4), reused 7 (delta 1)
170            Unpacking objects: 100% (10/10), done.
171            From ssh://rtime.felk.cvut.cz/osp/mc
172                 * [new branch]          master     -> osp/master
173                 * [new branch]          only-directories -> osp/only-directories
174
175 3. Příkaz nám vypíše, že v repozitáři byly dvě nové větve. Všechny
176    větve ze vzdálených repozitářů vypíšeme příkazem
177    
178        git branch -r
179    Zjednodušeně řečeno, jediný rozdíl mezi lokální a vzdálenou větví
180    je v tom, že jméno vzdálené větve má prefix `<remote>/`.
181
182 4. Nyní nás zajímá co je ve větvích, které jsme právě stáhli:
183
184        git log osp/only-directories ^master
185            git log master..osp/only-directories
186    Tyto dva příkazy jsou ekvivalentní a vypisují commity, které jsou
187    ve větvi *osp/only-directories* a zároveň nejsou (^) ve větvi *master*.
188    
189    Chcete-li vidět i změny v kódu použijte jeden z následujících příkazů:
190
191        git log -p osp/only-directories ^master
192            gitk osp/only-directories ^master
193
194 6. Podobně můžeme postupovat i s původním repozitářem. Jméno *origin*
195    je výchozí a proto ho nemusíme zadávat:
196
197        git fetch
198    Co přibylo ve větvi *master* od prvního cvičení zjistíme příkazem:
199    
200        git log master..origin/master
201
202 Slučování větví (merge)    
203 -----------------------
204
205 Operace slučující dvě a více větví do jedné se nazývá *merge*. V Gitu
206 Můžou při slučování nastat tři situace:
207
208 * *Already up-to-date* je situace, kdy už je větev, kterou chceme
209   sloučit, dosažitelná z aktuální větve (už byla sloučena v
210   minulosti). Při sloučení nedojde k žádné změně.
211 * *Fast-forward* je opak předchozí situace, tj. aktuální větev je
212   dosažitelná ze slučované větve. To odpovídá situaci, kdy
213   aktualizujeme na novější verzi. Při sloučení je větev (tj. ukazatel
214   na poslední commit) posunuta na novější verzi.
215 * *True merge*. Pokud nenastane jedna z předchozích situací, jedná se
216   o skutečné sloučení. Výsledek je nějaká kombinace obou verzí.
217   
218 Pokud došlo v případě *True merge* ke změně stejného místa v kódu v
219 obou větvích, dojde k tzv. *konfliktu*, který musí být vyřešen ručně.
220
221 1. Zkuste provést sloučení vaší větve *master* s *origin/master*
222
223        git merge origin/master
224    Výsledkem bude *Fast forward* a uvidíme jaké soubory byly změněny:
225
226        git merge origin/master
227        Updating 0ebd30c..a99dc51
228        Fast forward
229         configure.ac                  |    1 +
230         contrib/Makefile.am           |    9 +-
231         ...
232    Toto je velmi častá operace a proto lze operace `fetch` a `merge`
233    nahradit jedním příkazem
234
235        git pull
236 2. Vždy, když člověk pracuje na nějaké netriviální změně, je užitečné,
237    založit si na to samostatnou větev. Dnešním úkolem bude sloučit
238    větev *osp/only-directories* s větví *master* a protože to není
239    triviální založte si na to novou větev:
240    
241        git checkout -b homework
242 3. Pokud provedete sloučení
243
244        git merge osp/only-directories
245    Výsledek bude vypadat pravděpodobně takto:
246
247        Auto-merging doc/man/mc.1.in
248            Auto-merging src/filemanager/find.c
249            CONFLICT (content): Merge conflict in src/filemanager/find.c
250            Automatic merge failed; fix conflicts and then commit the result. 
251
252    Vidíme, že se automaticky povedlo sloučit změny v souboru
253    `doc/mc.1.in`, ale při slučování změn ve `src/find.c` už takové
254    štěstí nemáme a výsledkem je konflikt.
255         
256
257 Řešení konfliktů
258 ----------------
259
260 Konflikt lze řešit několika způsoby (viz také `git merge --help`):
261
262 * Vzdáme to a vrátíme se k verzi před slučováním
263
264        git reset --hard
265         
266 * Konflikt vyřešíme a oznámíme to gitu příkazy `git add` a `git
267   commit` (jak nám git napovídá v hláškách)
268
269 V průběhu řešení konfliktu je užitečné používat příkaz `git status`,
270 Abychom zjistili co je ještě potřeba vyřešit. V našem případě vypadá
271 Výstup zhruba takhle:
272    
273     # On branch homework
274     # Changes to be committed:
275     #
276     #   modified:   doc/man/mc.1.in
277     #
278     # Unmerged paths:
279     #   (use "git add/rm <file>..." as appropriate to mark resolution)
280     #
281     #   both modified:      src/filemanager/find.c
282
283 Konflikt lze řešit následujícími způsoby:
284
285 * V textovém editoru najdeme sekvence `<<<<<<<<`, `=========` a
286   `>>>>>>>>`, kterými jsou označené jednotlivé konfliktní oblasti.
287   Tato místa musíme opravit tak, aby dávala smysl a poté zmíněné
288   sekvence znaků smažeme.
289 * `git mergetool` je nástroj, který spouští grafický nástroj (např.
290   [kdiff3][kdiff3]), který vám se slučováním pomůže. 
291   
292   `kdiff3` vedle
293   sebe zobrazuje 3 různé verze projektu: poslední společná verze
294   (base), verzi z větve před slučováním (local) a verzi ze slučované
295   větve (remote) tj. té uvedené jako parametr v příkazu `git merge`.
296   
297   Ve spodní části obrazovky je pak vidět výsledek slučování, který
298   můžeme měnit buď přímou editací a nebo výběrem jednotlivých verzí
299   pomocí tlačítek A, B a C. V tomto okně je potřeba zbavit se všech
300   řádek, které mají v levém sloupci `?` - tj. konfliktů.
301 * `gitk --merge` - zobrazí pouze commity, které modifikovaly
302   konfliktní soubory.
303
304 [kdiff3]:http://kdiff3.sourceforge.net/
305
306 Repozitář na repo.or.cz
307 ---------------------------
308
309 K tomu, aby výsledky vaší práce na open source projektech byly snadno
310 Dostupné pro ostatní je užitečné založit si vlastní repozitář, odkud
311 si budou moct ostatní vaše změny stáhnout.
312
313 1. [Zaregistrujte se][reg] na [repo.or.cz][roc]. K repozitáři na
314    repo.or.cz se přistupuje protokolem SSH a autorizace se provádí na
315    základě veřejných klíčů.
316    
317    1. Pokud žádný klíč nemáte, vytvořte si ho příkazem 
318    
319           ssh-keygen
320
321       Příkaz se vás zeptá kam klíč uložit. Výchozí volba vám zpočátku
322       bude stačit. Dále se zeptá na heslo (passphrase) k vašemu
323       privátnímu klíči. Pokud žádné heslo nezadáte, bude se moct
324       kdokoli, kdo se dostane k souboru s vaším klíčem (např.
325       administrátor školních serverů), autorizovat jako vy.
326    
327    2. Pokud jste se rozhodli chránit klíč heslem, je otravné zadávat
328       heslo vždy, když klíč používáte. Naštěstí existuje program
329       `ssh-agent`, který uchovává odheslované klíče v paměti a
330       poskytuje je vždy, když je nějaký oprávněný program potřebuje.
331       Vy tak zadáte heslo jen jednou a to když předáváte klíč
332       ssh-agentovi příkazem
333
334           ssh-add
335
336 [reg]:http://repo.or.cz/reguser.cgi
337 [roc]:http://repo.or.cz/
338
339 2. Vytvoření repozitáře na repo.or.cz.
340
341    Můžete založit buď [nový projekt][new] a nebo udělat tzv.
342    [fork existujícího projektu][forkmc]. Pro oba typy projektů můžete
343    zvolit zda bude repozitář pouze automaticky aktualizovanou kopií
344    jiného repozitáře (*mirror mode*) a nebo zda-li bude možné do něj přímo
345    ukládat nové commity (*push mode*).
346    
347    Pro účely tohoto cvičení si
348    [založte fork][forkmc] [Midnight commanderu][w/osp.git] v *Push módu*, který se
349    bude jmenovat podle vašeho loginu. Do tohoto repozitáře pak
350    nahrajete úkol z dnešního cvičení.
351    
352 3. Do vašeho vzdáleného repozitáře můžete nahrát vaší větev některým z
353    těchto způsobů
354
355        git push ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git homework
356    nebo 
357
358        git remote add repo-or-cz ssh://<mujlogin>@repo.or.cz/srv/git/midnight-commander/osp/<mujfork>.git
359        git push repo-or-cz homework
360
361 [new]:http://repo.or.cz/regproj.cgi
362 [forkmc]:http://repo.or.cz/regproj.cgi?fork=midnight-commander/osp.git
363
364 Zadání
365 ======
366
367 Proveďte sloučení větve `ssh://git@rtime.felk.cvut.cz/osp/mc
368 only-directories` s aktuální vývojovou větví `origin/master`. Výsledek
369 uložte do [vámi vytvořeného repozitáře (forku) na repo.or.cz][forkmc]
370 do větve `homework`.
371
372 [w/osp.git]:http://repo.or.cz/w/midnight-commander/osp.git