Merge — шта је то, врсте спајања и механизам рада

Аутор: IT Sectr Објављено: 2026-05-10 Време читања: 10 мин

Merge — је операција у Git-у која обједињује измене из једне гране у другу, стварајући комит спајања (merge commit). Git подржава неколико стратегија: fast-forward (линеарна историја), three-way merge (са стварањем merge commit-а) и squash merge (сажимање свих комита у један). Према подацима git-scm.com, 2025, merge остаје најчешће коришћени механизам интеграције кода у тимском Git развоју.

Главно

  • Merge — операција спајања грана у Git-у са или без комита спајања
  • Fast-forward merge — линеарно спајање без додатног комита, када нема разилажења
  • Three-way merge — ствара merge commit при разилажењу грана
  • Squash merge — сажима све комите гране у један пре спајања
  • Конфликти настају при промени истих редова у обе гране

Шта је Merge?

Merge (спајање) — је фундаментална операција у Git-у која обједињује измене из једне гране (source) у другу (target). Као резултат спајања, циљна грана добија све комите из изворне гране којих још увек није било у њој. У зависности од ситуације, Git може извршити merge на три различита начина.

Основна вредност merge-а је очување историје: merge commit бележи чињеницу спајања грана, чува информацију о томе када и које гране су спојене. То олакшава ревизију промена, тражење регресија и разумевање хронологије развоја. У великим пројектима, merge commit је стандардни начин интеграције кода.

Према подацима GitLab Flow, merge commit-ови се користе у 73% тимова који раде са Git-ом. Алтернативне приступе (rebase, squash) преферирају тимови оријентисани на линеарну историју. Избор стратегије зависи од величине тима, учесталости издања и прихваћених договора у пројекту.

Када настаје Merge

Merge је потребан када је програмер завршио рад на функцији и жели да је интегрише у develop или main. Типичан сценарио: програмер је креирао грану функције од develop-а, радио неколико дана, а за то време су се у develop-у појавили нови комити од других учесника. Пре спајања потребно је објединити измене — и за то се користи merge.

Без merge-а није могуће заједнички радити на једном коду у Git-у. Сваки пут када два програмера истовремено уносе измене у исту базу кода, њихове гране се разилазе. Merge — једини начин да се те измене врате заједно без губитка података.

Врсте спајања у Git-у

Git подржава три врсте merge-а, од којих је свака намењена свом сценарију. Избор врсте спајања утиче на историју комита, удобност враћања и читљивост лога.

Fast-forward merge

Fast-forward настаје када циљна грана није имала нове комите од тренутка креирања изворне. У овом случају Git једноставно помера показивач циљне гране напред, на последњи комит изворне. Историја остаје линеарна, без merge commit-а.

bash
# Fast-forward merge: develop се није мењао од тренутка креирања feature
git checkout develop
git merge feature/new-login

# Резултат: показивач develop се померио на крај feature
# Није креиран ниједан merge commit

Fast-forward је погодан за краткотрајне гране, где је програмер радио сам. Али овај приступ има недостатак: губи се информација да је грана постојала — сви комити изгледају као да су направљени директно у develop-у.

Three-way merge

Three-way merge се извршава када обе гране имају нове комите после тачке разилажења. Git ствара посебан merge commit са два родитеља, који бележи чињеницу спајања грана. Овај приступ се препоручује за гране функција у тимском развоју.

bash
# Принудни three-way merge са заставицом --no-ff
git checkout develop
git merge --no-ff feature/new-login

# Креиран merge commit са подразумеваном поруком
# Може се поставити сопствена порука преко -m
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"

Заставица --no-ff гарантује стварање merge commit-а, чак и ако је fast-forward могућ. Ово је најбоља пракса за очување информације о гранању у пројекту.

Squash merge

Squash merge сажима све комите изворне гране у један и примењује га на циљну. Историја функције се губи — у грану стиже један комит са свим променама. Ово је згодно када детаљни комити у грани функције не носе вредност за општу историју.

bash
# Squash merge: сви комити feature-а сажети у један
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"

Squash је погодан за нацрте, експерименталне гране и ситуације када је важно одржати чистоту историје. Минус — губи се веза са оригиналним комитима, што отежава враћање појединачних промена.

Ours и Theirs стратегије

Ours и Theirs — две специјалне стратегије merge-а у Git-у. Ours потпуно игнорише измене из изворне гране, остављајући само оно што је у циљној. Theirs, напротив, прихвата верзију изворне гране при сваком конфликту. Ове стратегије су корисне при спајању великих количина кода, када је унапред познато која верзија треба да победи.

Како ради Merge

Механизам merge-а у Git-у се заснива на поређењу три тачке: заједничког претка (merge base), стања изворне гране и стања циљне гране. Git проналази merge base — последњи комит заједнички за обе гране — и израчунава које су промене настале у свакој грани после разилажења.

  • Корак 1 — Git одређује merge base: последњи комит који постоји у обе гране
  • Корак 2 — Git гради два диффа: од merge base до source и од merge base до target
  • Корак 3 — Git покушава да примени оба скупа промена на merge base
  • Корак 4 — Ако промене нису у сукобу — merge се завршава аутоматски
  • Корак 5 — Ако постоји конфликт — Git се зауставља и тражи решавање

Git користи тространи алгоритам спајања, који узима у обзир не само две упоређиване верзије датотеке, већ и њиховог заједничког претка. Захваљујући томе, Git може аутоматски да реши ситуације када промене у једној грани не утичу на измењене делове друге — чак и ако су обе датотеке измењене.

Алгоритам рада merge-а на примеру

Размотримо сценарио: два програмера раде на различитим датотекама у истој грани функције. Први је изменио LoginActivity.kt, други — ProfileFragment.kt. Када споје своје промене, Git види да су промене захватиле различите датотеке и извршава merge аутоматски, без људске интервенције.

Ако су оба програмера изменила LoginActivity.kt, али у различитим методама — Git ће се такође снаћи аутоматски, обједињујући промене ред по ред. Конфликт настаје само ако су оба изменила исте редове или ако је један обрисао код који је други изменио.

Решавање конфликата при Merge-у

Конфликт merge-а настаје када Git не може аутоматски да обједини промене, јер су обе гране измениле исте редове на различите начине. У овом случају Git означава конфликтне делове у датотекама и очекује ручно решавање од програмера.

Конфликтни делови се обележавају посебним маркерима: <<<<<<< HEAD приказује код из циљне гране, ======= — раздвајач, >>>>>>> source-branch — код из изворне гране. Програмер мора ручно да изабере коју варијанту да задржи или да их споји.

bash
# 1. Покренути merge и видети конфликт
git merge feature/new-login
# Излаз: CONFLICT (content): Merge conflict in LoginActivity.kt

# 2. Погледати листу датотека са конфликтима
git status
# both modified: src/ui/login/LoginActivity.kt

# 3. Решити конфликт: уредити датотеку, уклонити маркере
# 4. Додати решену датотеку и завршити merge
git add src/ui/login/LoginActivity.kt
git merge --continue
# или: git commit (без --continue)

За решавање конфликата постоје алати: git mergetool отвара визуелни merger (Meld, Beyond Compare, VS Code). Многи програмери преферирају да решавају конфликте у IDE-у — IntelliJ IDEA и Android Studio пружају уграђени алат са тропанелним поређењем, који значајно поједностављује овај процес.

Савети за решавање конфликата: увек разумите шта ради свака страна конфликта, не бришите туђи код без разумевања његове логике, а ако је конфликт превише сложен — укључите аутора обе гране у заједничко решавање.

Merge vs Rebase: када шта изабрати

Избор између Merge-а и Rebase-а — једна од најчешћих архитектонских одлука у Git-у. Оба приступа обједињују промене, али то чине различито: merge чува историју гранања, rebase преписује историју, чинећи је линеарном.

  • Merge — чува контекст: види се када и од које гране је извршено спајање. Бољи за јавне гране (develop, main) и тимски рад
  • Rebase — ствара чисту линеарну историју без сувишних merge commit-ова. Бољи за личне гране функција пре слања на преглед
  • Правило: никада не радите rebase јавних грана које користе други програмери

Многи тимови користе хибридни приступ: rebase за довођење гране функције у актуелно стање develop-а (git rebase develop), затим merge са заставицом --no-ff за фиксирање спајања. Ово даје чисту историју унутар функције и информативне тачке спајања на нивоу develop-а.

Често постављана питања

Која је разлика између merge и merge --no-ff?

Без --no-ff Git извршава fast-forward merge, ако је могуће — једноставно помера показивач гране. Са --no-ff Git увек ствара merge commit, чувајући информацију о гранању. Препоручује се за гране функција у тимском развоју.

Шта радити ако је merge конфликт веома велики?

Користите git mergetool или уграђени алат IDE-а. Ако конфликт захвата десетине датотека — можда су се гране превише разишле. У том случају вреди разговарати са тимом о плану спајања, можда га поделити у неколико фаза.

Може ли се отказати merge?

Да: git merge --abort отказује merge ако још није завршен (конфликт). Ако је merge већ завршен — користите git reset --hard HEAD~1 или git revert -m 1 <merge-commit> за безбедно враћање.

Да ли треба креирати merge commit за сваку функцију?

Препоручује се за тимски рад. Merge commit бележи чињеницу спајања, садржи референце на обе гране и поједностављује разумевање историје. За личне или експерименталне гране допуштен је squash merge или fast-forward.

Како merge ради са бинарним датотекама?

Git не може аутоматски да спаја бинарне датотеке — бира једну од верзија у целини. За бинарне датотеке (слике, .aab, .apk) препоручује се минимизирање паралелних измена и коришћење Git LFS за велике датотеке.

Закључци

  • Merge — основна операција Git-а за обједињавање промена из једне гране у другу
  • Fast-forward — линеарно спајање без merge commit-а, када нема разилажења
  • Three-way merge — ствара merge commit са два родитеља, чува контекст
  • Squash merge — сажима све комите гране у један, губећи историју функције
  • Конфликти настају при промени истих редова и решавају се ручно
  • Merge се разликује од Rebase-а: први чува гранање, други чини историју линеарном
  • За јавне гране препоручује се merge са --no-ff, за личне — rebase или squash

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође