forked from tkrajina/uvod-u-git
-
Notifications
You must be signed in to change notification settings - Fork 0
/
git-merge.tex
executable file
·516 lines (365 loc) · 23.7 KB
/
git-merge.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
\chapter*{Preuzimanje izmjena iz jedne grane u drugu}
\addcontentsline{toc}{chapter}{Preuzimanje izmjena iz jedne grane u drugu}
Vratimo se opet na već viđenu ilustraciju:
\input{graphs/git_merge_1}
Prebacivanjem na granu \verb+master+, izmjene koje smo napravili u \emph{commit}ovima \emph d, \emph e, \emph f i \emph g nam neće više biti dostupne.
Slično, prebacivanjem na \verb+eksperimentalna-grana+ -- neće nam biti dostupne izmjene iz \emph x, \emph y i \emph z.
To je u redu dok svoje izmjene želimo raditi u izolaciji od ostatka koda.
Što ako smo u \verb+eksperimentalna-grana+ ispravili veliki bug i htjeli bismo sad tu ispravku preuzeti u \verb+master+?
Ili, što ako zaključimo kako je rezultat eksperimenta kojeg smo isprobali u \\
\verb+eksperimentalna-grana+ uspješan i želimo to sad imati u \verb+master+?
Ono što nam sad treba je da nekako \textbf{izmjene iz jedne grane preuzmemo u drugu granu}.
U gitu, to se naziva \emph{merge}.
Iako bi merge mogli doslovno prevesti kao "spajanje", to nije ispravna riječ.
Rezultat spajanja bi bila samo jedna grana.
Nakon \emph{Merge}a dvije grane -- one nastavljaju svoj život.
Jedino što se sve izmjene koje su do tog trenutka rađene u jednoj granu preuzimaju u drugoj grani.
\section*{Git \emph{merge}}
\addcontentsline{toc}{section}{Git \emph{merge}}
Pretpostavimo, na primjer, da sve izmjene iz \verb+eksperimentalna-grana+ želimo u \verb+master+.
To se radi s naredbom \verb+git merge+, a da bi to napravili \textbf{trebamo se nalaziti u onoj grani u koju želimo preuzeti izmjene} (u našem slučaju \verb+master+).
Tada:
\input{git_output/git_merge_1}
Rezultat naredbe \verb+git merge+ je rekapitulacija procesa preuzimanja izmjena: koliko je linija dodano, koliko obrisano, koliko je datoteka dodano, koliko obrisano, itd\dots
Sve tu piše.
Još nešto je važno napomenuti -- ako je \verb+git merge+ proveden bez grešaka, to automatski dodaje novi \emph{commit} u grafu.
Ne moramo "ručno" \emph{commit}ati.
Grafički se \verb+git merge+ može prikazati ovako:
\input{graphs/git_merge_2}
Za razliku od svih ostalih \emph{commit}ova, ovaj ima dva "roditelja" iliti "prethodnika"\footnote{Ostali \emph{commit}ovi imaju ili jednog prethodnika ili nijednog -- ako se radi o prvom \emph{commit}u u repozitoriju.} -- jednog iz grane u kojoj se nalazi i drugog iz grane iz koje su izmjene preuzete.
Odnosno, na grafu čvor \emph d jedini ima dvije strelice koje idu "u njega".
Kad smo preuzeli izmjene iz jednog grafa u drugi -- obje grane mogu uredno nastaviti svoj dosadašnji "život".
U obje možemo uredno \emph{commit}ati, preuzimati izmjene iz jedne grane u drugu, i sl.
Kasnije možemo i ponoviti preuzimanje izmjena, odnosno \emph{merge}anje.
I, eventualno, jednog dana kad odlučimo da nam grana više ne treba, možemo ju obrisati.
\section*{Što \emph{merge} radi kad\dots}
\addcontentsline{toc}{section}{Što \emph{merge} radi kad\dots}
Vjerojatno se pitate što je rezultat \emph{merge}anja u različitim situacijama.
Na primjer u jednog grani smo dodali datoteku, a u drugoj editirali ili u jednoj editirali početak datoteke, a u drugoj kraj iste ili\dots
U principu, vjerujte mi, git najčešće napravi točno ono što treba.
Kad sam ga ja počeo koristiti imao sam malu tremu prije svakog \verb+git merge+.
Jednostavno, iskustvo CVS-om, SVN-om i TFS-om mi nije baš ulijevalo povjerenja u to da ijedan sustav za verzioniranje koda zna ovu radnju izvršiti kako treba.
Nakon svakog \emph{merge}a sam išao proučavati je li rezultat ispravan i provjeravao bih da mi nije možda pregazio neku datoteku ili važan komad koda.
Rezultat tog neformalnog istraživanja je: Moja (ljudska) i gitova (mašinska) intuicija o tome što treba napraviti se skoro uvijek poklapaju.
Umjesto beskonačnih hipotetskih situacija tipa "Što će git napraviti ako sam u grani $A$ izmijenio $x$, a u grani $B$ izmijenio $y$\dots" -- najbolje je da to jednostavno isprobate.
U ostatku ovog poglavlja ćemo samo proći nekoliko posebnih situacija.
Uzmimo poznati slučaj:
\input{graphs/git_merge_2}
Dakle, što će biti rezultat \emph{merge}anja, ako\dots
\begin{itemize}
\item \dots{}u eksperimentalnoj grani smo izmijenili datoteku, a u \verb+master+ nismo -- izmjene iz eksperimentalne će se dodati u \verb+master+.
\item \dots{}u eksperimentalnoj grani smo dodali datoteku -- ta datoteka će biti dodana i u \verb+master+.
\item \dots{}u eksperimentalnoj grani smo izbrisali datoteku -- datoteka će biti obrisana u glavnoj.
\item \dots{}u eksperimentalnoj grani smo \textbf{izmijenili i preimenovali} datoteku, a u \verb+master+ ste samo izmijenili datoteku -- ako izmjene na kodu nisu bile \textbf{konfliktne}, onda će se u \verb+master+ datoteka preimenovati i sadržavati će izmjene iz obje grane.
\item \dots{}u eksperimentaloj grani smo obrisali datoteku, a u glavnoj ju izmijenili -- \textbf{konflikt}.
\item itd\dots
\end{itemize}
Vjerojatno slutite što znači ova riječ koja je ispisana masnim slovima: \textbf{konflikt}.
Postoje slučajevi u kojima git ne zna što napraviti.
I tada se očekuje od korisnika da sam riješi problem.
\section*{Što se desi kad\dots}
\addcontentsline{toc}{section}{Što se desi kad\dots}
Stvar nije uvijek tako jednostavna.
Dogoditi će se da u jednoj grani napravite izmjenu u jednoj datoteci, a u drugoj grani napravite izmjenu na \emph{istoj} datoteci.
I što onda?
Pokušat ću to ilustrirati na jednom jednostavnom primjeru\dots
Uzmimo hipotetski scenarij -- neka je Antun Branko Šimić još živ i piše pjesme.
Napiše pjesmu, pa s njome nije baš zadovoljan, pa malo križa po papiru, pa izmijeni prvi stih, pa izmijeni zadnji stih.
Ponekad mu se rezultat sviđa, ponekad ne.
Ponekad krene iznova.
Ponekad ima ideju, napiše nešto nabrzinu, i onda kasnije napravi dvije verzije iste pjesme.
Ponekad\dots
Kao stvoreno za git, nije li?
Recimo da je autor krenuo sa sljedećom verzijom pjesme:
\gitoutput{%
PJESNICI U SVIJETU\\%
\\%
Pjesnici su čuđenje u svijetu\\%
\\%
Oni idu zemljom i njihove oči\\%
velike i nijeme rastu pored stvari\\%
\\%
Naslonivši uho\\%
na tišinu sto ih okružuje i muči\\%
oni su vječno treptanje u svijetu}
I sad ovdje nije baš bio zadovoljan sa cjelinom i htio bi isprobati dvije varijante.
Budući da ga je netko naučio git, iz početnog stanja (\emph a) napravio je dvije verzije.
\input{graphs/ab_simic_1}
U prvoj varijanti (\emph b), izmijenio je naslov, tako da je sad pjesma glasila:
\gitoutput{%
\textcolor{blue}{PJESNICI}\\%
\\%
Pjesnici su čuđenje u svijetu\\%
\\%
Oni idu zemljom i njihove oči\\%
velike i nijeme rastu pored stvari\\%
\\%
Naslonivši uho\\%
na tišinu sto ih okružuje i muči\\%
oni su vječno treptanje u svijetu}
\dots{}dok je u drugoj varijanti (\emph c) izmijenio zadnji stih:
\gitoutput{%
PJESNICI U SVIJETU\\%
\\%
Pjesnici su čuđenje u svijetu\\%
\\%
Oni idu zemljom i njihove oči\\%
velike i nijeme rastu pored stvari\\%
\\%
Naslonivši uho\\%
\textcolor{blue}{na ćutanje sto ih okružuje i muči\\%
pjesnici su vječno treptanje u svijetu}}
S obzirom da je bio zadovoljan s oba riješenja, odlučio je izmjene iz varijante \verb+varijanta+ preuzeti u \verb+master+.
Nakon \verb+git checkout master+ i \verb+git merge varijanta+, rezultat je bio:
\input{graphs/ab_simic_2}
\dots{}odnosno, pjesnikovim riječima:
\gitoutput{%
\textcolor{blue}{PJESNICI}\\%
\\%
Pjesnici su čuđenje u svijetu\\%
\\%
Oni idu zemljom i njihove oči\\%
velike i nijeme rastu pored stvari\\%
\\%
Naslonivši uho\\%
\textcolor{blue}{na ćutanje sto ih okružuje i muči\\%
pjesnici su vječno treptanje u svijetu}}
I to je jednostavno.
U obje grane je mijenjao istu datoteku, ali u jednoj je dirao početak, a u drugoj kraj.
I rezultat \emph{merge}anja je bio očekivan -- datoteka u kojoj je izmijenjen i početak i kraj.
\section*{Konflikti}
\addcontentsline{toc}{section}{Konflikti}
Što da je u obje grane dirao isti dio pjesme?
Što da je nakon:
\input{graphs/ab_simic_1}
\dots{} stanje bilo ovakvo:
U verziji \emph a je pjesma sad glasila:
\gitoutput{%
PJESNICI\\%
\\%
Pjesnici su čuđenje u svijetu\\%
\\%
\textcolor{blue}{Pjesnici idu zemljom i njihove oči\\%
velike i nijeme rastu pored ljudi}\\%
\\%
Naslonivši uho\\%
na ćutanje sto ih okružuje i muči\\%
pjesnici su vječno treptanje u svijetu}
\dots{}a u verziji \emph b ovako:
\gitoutput{%
PJESNICI\\%
\\%
Pjesnici su čuđenje u svijetu\\%
\\%
\textcolor{blue}{Oni idu zemljom i njihova srca\\%
velika i nijema rastu pored stvari}\\%
\\%
Naslonivši uho\\%
na ćutanje sto ih okružuje i muči\\%
pjesnici su vječno treptanje u svijetu}
Sad je rezultat naredbe \verb+git merge varijanta+ ovakav:
\input{git_output/git_merge_konflikt}
To znači da git nije znao kako da \emph{automatski} preuzme izmjene iz \emph b u \emph a.
Idete li sad editirati datoteku s pjesmom naći ćete ovakvo nešto:
\gitoutput{%
PJESNICI U SVIJETU\\%
\\%
Pjesnici su čudenje u svijetu\\%
\\%
\textcolor{red}{<<<<<<< HEAD\\%
Oni idu zemljom i njihova srca\\%
velika i nijema rastu pored stvari\\%
=======\\%
Pjesnici idu zemljom i njihove oči\\%
velike i nijeme rastu pored ljudi\\%
>>>>>>> eksperimentalna-grana}\\%
\\%
Naslonivši uho na tišinu sto ih okružuje i muči\\%
oni su vječno treptanje u svijetu}
Dakle, dogodio se \textbf{konflikt}.
U crveno je obojan dio za kojeg git ne zna kako ga \emph{merge}ati.
S \verb+HEAD+ je označeno stanje iz trenutne grane, a s \verb+eksperimentalna-grana+ iz druge grane.
Za razliku od standardnog \emph{merge}, ovdje niti jedna datoteka nije \emph{commit}ana.
To možete lako provjeriti sa \verb+git status+:
\input{git_output/git_merge_konflikt_2}
Sad se od autora očekuje da sam odluči kako će izgledati datoteka nakon \emph{merge}a.
Jednostavan način je da editira tu datoteku i sam ju izmijeni kako želi.
Nakon toga treba ju \emph{commit}ati na standardan način.
Drugi način je da koristite \verb+git mergetool+.
Ako se sjećate početka ove knjige, govorilo se o standardnoj konfiguraciji.
Jedna od opcija je tamo bila i "mergetool", a to je program s kojim lakše rješavate ovakve konflikte.
Iako to nije nužno (možete uvijek sami editirati konfliktne datoteke) -- to je zgodno riješenje ako znate raditi s nekim od programa za rješavanje konflikata.
Na primjer, ako koristite vimdiff, onda editiranje konfliktnih datoteka izgleda ovako:
\gitgraphics{images/mergetool.png}
Nakon što konflikt u datoteci (ili datotekama) riješite -- izmijenjene datoteke treba \emph{commit}ati.
\section*{\emph{Merge}, \emph{branch} i povijest projekta}
\addcontentsline{toc}{section}{\emph{Merge}, \emph{branch} i povijest projekta}
Kad radimo s nekim projektom, onda nam je važno da imamo sačuvanu cijelu njegovu povijest.
To nam omogućava da saznamo tko je originalni autor koda kojeg možda slabije razumijemo.
Ili želimo vidjeti kojim redosljedom je neka datoteka nastajala.
Sa standardnim sustavima za verzioniranje, stvar je jednostavna.
Grananje i preuzimanje izmjena iz jedne u drugu granu je bilo komplicirano i rijetko se radilo.
Posljedica je da su projekti najčešće imali linearnu povijest.
\input{graphs/linearni_model}
S gitom, često imamo po nekoliko grana.
Svaka od tih grana ima svoju povijest, a kako se povećava broj grana, tako organizacija projekta postaje veći izazov.
I zato mnogi programeri grane koje više ne koriste brišu.
Tu sad imamo mali problem.
Pogledajte, na primjer, ovakav projekt:
\input{graphs/git_merge_2}
Eksperimentalna grana ima svoju povijest, a u trenutku \emph{merge}a, sve izmjene iz te grane su se "prelile" u \verb+master+ i to u \emph{commit} \emph d.
Postoje situacije u kojima moramo gitovu "razgranatu" povijest svesti na linearnu\footnote{Na primjer, ako koristimo git kao subversion ili tfs klijent. Da, i to se može!}.
U drugim situacijama, jednostavno želimo imati ljepši (linearni!) pregled povijesti projekta.
To se može riješiti nečime što se zove \emph{rebase}.
Da bi to mogli malo bolje objasniti, potrebno je napraviti digresiju u jednu posebnu vrstu \emph{merge}a -- \emph{fast forward}\dots
\section*{\emph{Fast forward}}
\addcontentsline{toc}{section}{\emph{Fast forward}}
Nakon objašnjenja s prethodnih nekoliko stranica, trebalo bi biti jasno što će se dogoditi ako želimo preuzeti izmjene iz \verb+varijanta+ u \verb+master+ u projektu koji ima ovakvu povijest:
\input{graphs/bez_fast_forward}
To je najobičniji \emph{merge} dvije grane.
Razmislimo samo, na trenutak, o jednom očitom detalju;
osnovna pretpostavka i smisao preuzimanja izmjena iz jedne grane u drugu je to što uopće imamo dvije grane.
To su ove dvije crte u gornjem grafu.
Dakle, sve to ima smisla u projektu koji ima nelinearnu povijest (više grana).
Postoji jedan poseban slučaj koji zahtijeva pojašnjenje.
Uzmimo da je povijest projekta bila slična gornjem grafu, ali s jednom malo izmjenom:
\input{graphs/fast_forward}
Programer je napravio novu granu \verb+varijanta+ i na njoj je nastavio rad.
I svo to vrijeme nije radio nikakve izmjene na \verb+master+.
Što kad sad želi preuzeti sve izmjene u \verb+master+?
Uočavate li što je ovdje neobično?
Smisao \emph{merge}anja je u tome da neke izmjene iz jedne grane preuzmemo u drugu.
Međutim, iako ovdje imamo dvije grane, \textbf{te dvije grane čine jednu crtu}.
One imaju jednu povijest.
I to linearnu povijest.
Jedino što se ta linearna povijest proteže kroz obje grane.
Tako su razmišljali i originalni autori gita.
U git su ugradili automatsko prepoznavanje ovakve situacije i zato, umjesto standardnog \emph{merge}a, koji bi izgledao ovako:
\input{graphs/fast_forward_2}
\dots{}git izvršava takozvani \emph{fast-forward merge}:
\input{graphs/fast_forward_3}
Dakle, kopira cijelu povijest (ovdje je to \emph x, \emph y i \emph z) u novu granu%
\footnote{Preciznije, čvorovi $x$, $y$ i $z$ se sad nalaze u dvije grane. U gitu jedan \emph{commit} može biti dio više različitih grana.}%
.
Čak i ako sad obrišete \verb+varijanta+, cijela njegova povijest se nalazi u \verb+master+.
Git sam odlučuje je li potrebno izvršiti \emph{fast-forward merge} i izvršava ga.
Želimo li ga izbjeći -- to se radi tako da dodamo opciju \verb+--no-ff+ naredbi \verb+git merge+:
\gitoutputcommand{git merge --no-ff varijanta}
\section*{\emph{Rebase}}
\addcontentsline{toc}{section}{\emph{Rebase}}
Idemo, još jednom, pogledati linearni model:
\input{graphs/linearni_model}
Do sada bi svima trebalo biti jasno da on ima svoje nedostatke, ali ima i pozitivnih strana -- jednostavna i pregledna povijest projekta i privid da je sve skupa teklo po nekom točno određenom rasporedu.
Korak po korak, do trenutne verzije.
Git nas ne tjera da radimo grane, no postupak grananja čini bezbolnim.
I zbog toga povijest projekta \textbf{može} postati cirkus kojeg je teško pratiti i organizirati.
Organizacija repozitorija zahtijeva posebnu pažnju, posebno ako radite s više ljudi na istom projektu.
Postoji, ipak, način kako se može od puno grana stvoriti linearna povijest.
Kad bi postojao trik kako da iz ovakvog stanja:
\input{graphs/bez_fast_forward}
\dots{}stvorimo ovo:
\input{graphs/bez_fast_forward_rebase}
To jest, da \emph{pomaknemo mjesto od kud smo granali} neku granu.
Tada bi \emph{fast-forward} samo kopirao cijelu našu granu u \verb+master+.
Nakon toga bi brisanjem grane \verb+varijanta+ dobili da je povijest našeg projekta postala linearna:
\input{graphs/bez_fast_forward_rebase_2}
Taj trik postoji i zove se \emph{rebase}.
Radi se na sljedeći način; trebamo biti postavljeni u grani koju želimo "pomaknuti". Zatim \verb+git rebase <grana>+, gdje je \verb+<grana>+ ona grana na kojoj kasnije treba izvršiti \emph{fast-forward}.
Želimo li granu \verb+test+ "pomaknuti" na kraj grane \verb+master+, (to jest, izvršiti \emph{rebase}):
\gitoutputcommand{git rebase master}
U idealnoj situaciji, git će znati riješiti sve probleme i rezultat naredbe će izgledati ovako:
\input{git_output/git_rebase}
Međutim, ovdje mogu nastati problemi slični klasičnom \emph{merge}u.
Tako da će se ponekad dogoditi:
\input{git_output/git_rebase_konflikt}
Pogledate li konfliktne datoteke, vidjeti ćete da je njihov format isti kao kod konflikta pri \emph{merge}u.
Na isti način se od nas očekuje da konflikte riješimo.
Bilo koristeći \verb+git mergetool+, bilo tako da editiramo datoteku i ispravimo ju tako da dobijemo željeno stanje.
Kod grananja su konflikti vjerojatno malo jasniji -- točno znamo da jedna izmjena dolazi iz jedne grane, a druga iz druge.
Ovdje će nam se možda dogoditi\footnote{Meni jest, puno puta} da nismo točno sigurni koju konfliktnu izmjenu uzeti.
Ili ostaviti obje.
Promotrimo, zato, još jednom grafički prikaz onoga što pokušavamo napraviti:
\input{graphs/fast_forward_4}
Naš cilj je preseliti \textcolor{gray}{sivi} dio tako da postane \textcolor{blue}{plavi}.
Drugim riječim, izmjene koje smo napravili u \emph d, \emph e i \emph f treba nekako "ugurati" prije \emph x, \emph y i \emph z.
Tako ćemo stvoriti novu granu koja se sastoji \emph{x'}, \emph{y'} i \emph{z'}.
Konflikt se može dogoditi u trenutku kad git "seli" $x$ u $x'$, ili $y$ u $y'$ ili $z$ u $z'$.
Recimo da je konflikt nastao u prvom slučaju ($x$ u $x'$).
Negdje u čvorovima $d$, $e$ i $f$ je mijenjan isti kod koji smo mi mijenjali u $x$\footnote{Primijetite da bi do ovog konflikta došli i s klasičnim \emph{merge}om.}.
Mi ovdje želimo zadržati povijest iz svih \emph{commit}ova: $d$, $e$, $f$, $x$, $y$ i $z$.
To treba imati na umu dok odlučujemo kako ćemo ispraviti konflikt.
U slučaju konflikta, često ćemo htjeti zadržati obje verzije konfliktnog koda, treba samo pripaziti na njihov redosljed i potencijalne sitne bugove koji mogu nastati.
Nakon što smo konflikt ispravili, \textbf{ne smijemo izmjene \emph{commit}ati, nego samo spremiti u indeks s} \verb+git add+.
Nastavljamo s:
\gitoutputcommand{git rebase --continue}
Ponekad će git znati izvršiti ostatak procesa automatski, a može se dogoditi i da ne zna i opet od nas traži da ispravimo sljedeći konflikt.
U boljem slučaju (sve automatski), rezultat će biti:
\input{git_output/git_rebase_konflikt_continue}
\dots{}i sad smo slobodni smo izvesti \emph{merge}, koji će u ovom slučaju sigurno biti \emph{fast-forward}, a to je upravo ono što smo htjeli.
Ako \emph{rebase} ima previše konflikata -- možda se odlučimo odustati od nastavka.
Prekid \emph{rebase}a i vraćanje repozitorija u stanje prije nego što smo ga pokrenuli možemo obaviti s:
\gitoutputcommand{git rebase --abort}
\section*{\emph{Rebase} ili ne \emph{rebase}?}
\addcontentsline{toc}{section}{\emph{Rebase} ili ne \emph{rebase}?}
Rebase nije nužno raditi.
Na vama je odluka želite li jednostavniju (linearnu) povijest projekta ili ne.
Postoji jedan način korištenja gita u kojem je \emph{rebase} važan.
To je \textbf{ako koristite git kao CVS, subversion ili TFS klijent}.
Nećemo ovdje u detalje, ali recimo to ovako -- da, moguće je koristiti git kao klijent za druge (standardne) sustave za verzioniranje\footnote{Uz instalaciju posebnih \emph{plugin}ova, naravno.}.
\emph{Commit}ovi koji su slika udaljenog repozitorija se, u takvim slučajevima, uvijek čuvaju u posebnoj grani.
Dakle, jedna grana je doslovna kopija udaljenog repozitorija (CVS, subversion ili TFS).
Tu granu možemo osvježavati s novim \emph{commit}ovima iz centralnog repozitorija.
Našu gitovsku čudnovatu i razgranatu povijest treba svesti na povijest kakvu ti repozitoriji najbolje razumiju, a to je linearna.
Zato, kad treba \emph{commit}ati naše izmjene -- sve što smo radili u drugim granama treba "preseliti" na kraj grane koja je kopija centralnog repozitorija.
Taj postupak nije ništa drugo nego \emph{rebase}.
Tek tada možemo \emph{commit}ati.
S obzirom da centralizirani sustavi za verzioniranje više vole linearnu od razgranate povijesti -- moramo igrati po njihovim pravilima, a \emph{rebase} je jedini način da to učinimo.
\section*{\emph{Cherry-pick}}
\addcontentsline{toc}{section}{\emph{Cherry-pick}}
Ima još jedna posebna vrsta \emph{merge}a, a nosi malo neobičan naziv \emph{cherry-pick}\footnote{Engleski: branje trešanja. U prenesenom značenju: ispričati priču samo sa onim detaljima koji su pripovjedaču važni. Iliti, izbjegavanje onih dijelova priče koje pripovjedač ne želi.}.
Pretpostavimo da imamo dvije grane:
\input{graphs/git_merge_1}
U \verb+eksperimentalna-grana+ smo napravili nekoliko izmjena i sve te izmjene \emph{nisu} još spremne da bismo ih prebacili u \verb+master+.
Međutim, ima jedan \emph{commit} (recimo da je to \emph g) s kojim smo ispravili mali bug koji se manifestirao i u \verb+master+ grani.
Klasični \emph{merge} oblika:
\input{graphs/git_merge_2}
\dots{}ne dolazi u obzir, jer bi on u \verb+master+ prebacio sve izmjene koje smo napravili u \emph d, \emph e, \emph f i \emph g.
Mi želimo samo i isključivo \emph g.
To se, naravno, može i to je (naravno) taj \emph{cherry-pick}.
Postupak je sljedeći: prvo promotrimo povijest grane \verb+eksperimentalna-grana+:
\input{git_output/git_log_za_cherry_pick}
Kao što ste vjerojatno već primijetili, svaki \emph{commit} u povijesti ima neki čudan string kao \verb+5c843fbfb09382c272ae88315eea9d77ed699083+.
Taj string jedinstveno određuje svaki \emph{commit} (više riječi o tome u posebnom poglavlju).
Sad trebamo naći takav identifikator za onaj commit kojeg želite prebaciti u \verb+master+. Recimo da je to \verb+2b9ef6d02e51a890d508413e83495c11184b37fb+.
Prebacimo se u granu u koju želimo preuzeti samo izmjene iz tog \emph{commit}a i utipkajmo \verb+git cherry-pick <commit>+.
Ako nema konflikata, rezultat će biti:
\input{git_output/git_cherry_pick}
\dots{}a, ako imamo konflikata onda\dots
To već znamo riješiti, nadam se.
\section*{Merge bez \emph{commit}a\footnote{Ovaj naslov se odnosi samo na starije git klijente.}}
\addcontentsline{toc}{section}{Merge bez \emph{commit}a}
Vratimo se opet na klasični \emph{merge}.
Ukoliko je prošao bez ikakvih problema, onda ćemo nakon\dots
\input{graphs/git_merge_2}
\dots{}u povijesti projekta vidjeti nešto kao:
\input{git_output/git_merge_log}
Ukoliko koristite neku noviju verziju gita, onda će on kod nakon \emph{merge}a otvoriti editor i ponuditi vam da sami upišete poruku za taj \emph{commit}.
No, ako niste na najnovijoj verziji\dots
Ako se već odlučimo da ne želimo \emph{rebase} -- u povijesti ćemo imati puno grana i čvorova u kojima se one spajaju.
Bilo bi lijepo u kad bi umjesto \texttt{Merge branch 'eksperimentalna-grana'} imati smisleniji komentar koji bi bolje opisao što smo točno u toj grani napravili.
To se može tako da, umjesto \verb+git merge eksperimentalna-grana+ \emph{merge}, izvršimo s:
\gitoutputcommand{git merge eksperimentalna-grana --no-commit}
Na taj naćin če se \emph{merge} izvršiti, ali neće se sve \emph{commit}ati.
Sad možemo \emph{commit}ati sa svojim komentarom ili eventualno napraviti još koju izmjenu prije nego se odlučimo snimiti novo stanje.
Jedini detalj na kojeg treba pripaziti je što, ako je došlo do \emph{fast-forward} \emph{merge}anja, onda \verb+--no-commit+ nema efekta.
Zato je, za svaki slučaj, bolje koristiti sljedeću sintaksu:
\gitoutputcommand{git merge eksperimentalna-grana --no-ff --no-commit}
Ukoliko ste zaboravili \verb+--no-commit+, tekst poruke zadnjeg \emph{commit}a možete ispraviti i s \emph{amend commit}om.
\section*{\emph{Squash merge}}
\addcontentsline{toc}{section}{\emph{Squash merge}}
Još jedna ponekad korisna opcija kod \emph{merge}a je, takozvani \emph{squash merge}.
Radi se o sljedećem, klasični \emph{merge} stvara commit kao $d$ u grafu:
\input{graphs/git_merge_2}
Čvor $d$ ima dva prethodnika: $q$ i $d$.
Ukoliko želimo da $d$ \textbf{ima} izmjene iz grane \verb+eksperimentalna-grana+, ali \textbf{ne želimo} da $d$ ima referencu na tu granu, to se dobije s\footnote{Ne brinite se ako vam ne pada na pamet scenarij u kojem bi to moglo trebati. Ni meni nije do jutros :)}:
\gitoutputcommand{git merge --squash eksperimentalna-grana}