Merge — co to jest, typy scalania i mechanizm działania

Autor: IT Sectr Opublikowano: 2026-05-10 Czas czytania: 10 min

Merge — to operacja w Git, która łączy zmiany z jednej gałęzi do drugiej, tworząc commit scalania (merge commit). Git obsługuje kilka strategii: fast-forward (liniowa historia), three-way merge (z utworzeniem merge commit) i squash merge (skompresowanie wszystkich commitów w jeden). Według danych git-scm.com, 2025, merge pozostaje najczęściej używanym mechanizmem integracji kodu w zespołowej pracy z Git.

Najważniejsze

  • Merge — operacja scalania gałęzi w Git z utworzeniem lub bez commitu scalania
  • Fast-forward merge — liniowe scalanie bez dodatkowego commitu, gdy nie ma rozbieżności
  • Three-way merge — tworzy merge commit przy rozbieżności gałęzi
  • Squash merge — kompresuje wszystkie commity gałęzi w jeden przed scalaniem
  • Konflikty powstają przy zmianie tych samych wierszy w obu gałęziach

Co to jest Merge?

Merge (scalanie) — to fundamentalna operacja w Git, która łączy zmiany z jednej gałęzi (source) do drugiej (target). W wyniku scalania gałąź docelowa otrzymuje wszystkie commity z gałęzi źródłowej, których jeszcze w niej nie było. W zależności od sytuacji Git może wykonać merge na trzy różne sposoby.

Główną wartością merge jest zachowanie historii: merge commit rejestruje fakt połączenia gałęzi, przechowuje informację o tym, kiedy i które gałęzie zostały scalone. Ułatwia to audyt zmian, wyszukiwanie regresji i zrozumienie chronologii rozwoju. W dużych projektach merge commit jest standardowym sposobem integracji kodu.

Według danych GitLab Flow, merge commity są używane w 73% zespołów pracujących z Git. Alternatywne podejścia (rebase, squash) preferują zespoły nastawione na liniową historię. Wybór strategii zależy od wielkości zespołu, częstotliwości wydań i przyjętych w projekcie ustaleń.

Kiedy występuje Merge

Merge jest wymagany, gdy programista zakończył pracę nad funkcją i chce zintegrować ją z develop lub main. Typowy scenariusz: programista utworzył gałąź funkcji od develop, pracował w niej kilka dni, a w tym czasie w develop pojawiły się nowe commity od innych uczestników. Przed scalaniem trzeba połączyć zmiany — i do tego służy merge.

Bez merge niemożliwa jest wspólna praca nad jednym kodem w Git. Za każdym razem, gdy dwóch programistów jednocześnie wprowadza zmiany do tej samej bazy kodu, ich gałęzie się rozchodzą. Merge — to jedyny sposób, aby połączyć te zmiany z powrotem bez utraty danych.

Rodzaje scalania w Git

Git obsługuje trzy typy merge, z których każdy jest przeznaczony do swojego scenariusza. Wybór typu scalania wpływa na historię commitów, wygodę wycofywania i czytelność logu.

Fast-forward merge

Fast-forward występuje, gdy gałąź docelowa nie miała nowych commitów od momentu utworzenia źródłowej. W tym przypadku Git po prostu przesuwa wskaźnik gałęzi docelowej do przodu, na ostatni commit źródłowej. Historia pozostaje liniowa, bez merge commitu.

bash
# Fast-forward merge: develop nie zmieniał się od momentu utworzenia feature
git checkout develop
git merge feature/new-login

# Wynik: wskaźnik develop przesunął się na koniec feature
# Nie utworzono żadnego merge commitu

Fast-forward jest wygodny dla krótko żyjących gałęzi, gdzie programista pracował samodzielnie. Ale to podejście ma wadę: traci się informację o tym, że gałąź istniała — wszystkie commity wyglądają jak zrobione bezpośrednio w develop.

Three-way merge

Three-way merge jest wykonywany, gdy obie gałęzie mają nowe commity po punkcie rozbieżności. Git tworzy osobny merge commit z dwoma rodzicami, który rejestruje fakt połączenia gałęzi. To podejście jest zalecane dla gałęzi funkcyjnych w pracy zespołowej.

bash
# Wymuszony three-way merge z flagą --no-ff
git checkout develop
git merge --no-ff feature/new-login

# Utworzono merge commit z domyślną wiadomością
# Można ustawić własną wiadomość przez -m
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"

Flaga --no-ff gwarantuje utworzenie merge commitu, nawet jeśli fast-forward jest możliwy. To najlepsza praktyka dla zachowania informacji o rozgałęzieniach w projekcie.

Squash merge

Squash merge kompresuje wszystkie commity gałęzi źródłowej w jeden i stosuje go do docelowej. Historia funkcji zostaje utracona — do gałęzi trafia jeden commit ze wszystkimi zmianami. Jest to wygodne, gdy szczegółowe commity w gałęzi funkcji nie niosą wartości dla ogólnej historii.

bash
# Squash merge: wszystkie commity feature skompresowane w jeden
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"

Squash nadaje się do wersji roboczych, gałęzi eksperymentalnych i sytuacji, gdy ważne jest zachowanie czystości historii. Minus — traci się związek z oryginalnymi commitami, co utrudnia wycofywanie poszczególnych zmian.

Strategie Ours i Theirs

Ours i Theirs — dwie specjalne strategie merge w Git. Ours całkowicie ignoruje zmiany z gałęzi źródłowej, pozostawiając tylko to, co jest w docelowej. Theirs, przeciwnie, przyjmuje wersję gałęzi źródłowej przy każdym konflikcie. Te strategie są przydatne przy scalaniu dużych ilości kodu, gdy z góry wiadomo, która wersja ma zwyciężyć.

Jak działa Merge

Mechanizm merge w Git opiera się na porównaniu trzech punktów: wspólnego przodka (merge base), stanu gałęzi źródłowej i stanu gałęzi docelowej. Git znajduje merge base — ostatni commit wspólny dla obu gałęzi — i oblicza, jakie zmiany zaszły w każdej gałęzi po rozbieżności.

  • Krok 1 — Git określa merge base: ostatni commit, który istnieje w obu gałęziach
  • Krok 2 — Git buduje dwa diffy: od merge base do source i od merge base do target
  • Krok 3 — Git próbuje zastosować oba zestawy zmian do merge base
  • Krok 4 — Jeśli zmiany nie kolidują — merge kończy się automatycznie
  • Krok 5 — Jeśli występuje konflikt — Git zatrzymuje się i prosi o rozwiązanie

Git używa trójstronnego algorytmu scalania, który uwzględnia nie tylko dwie porównywane wersje pliku, ale także ich wspólnego przodka. Dzięki temu Git może automatycznie rozwiązywać sytuacje, gdy zmiany w jednej gałęzi nie dotyczą zmienionych fragmentów drugiej — nawet jeśli oba pliki zostały zmodyfikowane.

Algorytm działania merge na przykładzie

Rozważmy scenariusz: dwóch programistów pracuje nad różnymi plikami w jednej gałęzi funkcji. Pierwszy zmienił LoginActivity.kt, drugi — ProfileFragment.kt. Kiedy łączą swoje zmiany, Git widzi, że zmiany dotyczyły różnych plików, i wykonuje merge automatycznie, bez interwencji człowieka.

Jeśli obaj programiści zmienili LoginActivity.kt, ale w różnych metodach — Git również poradzi sobie automatycznie, łącząc zmiany wiersz po wierszu. Konflikt powstaje tylko wtedy, gdy obaj zmienili te same wiersze lub jeśli jeden usunął kod, który drugi zmienił.

Rozwiązywanie konfliktów przy Merge

Konflikt merge powstaje, gdy Git nie może automatycznie połączyć zmian, ponieważ obie gałęzie zmodyfikowały te same wiersze w różny sposób. W takim przypadku Git oznacza konfliktowe fragmenty w plikach i oczekuje ręcznego rozwiązania przez programistę.

Konfliktowe fragmenty są oznaczane specjalnymi znacznikami: <<<<<<< HEAD pokazuje kod z gałęzi docelowej, ======= — separator, >>>>>>> source-branch — kod z gałęzi źródłowej. Programista musi ręcznie wybrać, który wariant pozostawić, lub połączyć je.

bash
# 1. Uruchomić merge i zobaczyć konflikt
git merge feature/new-login
# Wynik: CONFLICT (content): Merge conflict in LoginActivity.kt

# 2. Wyświetlić listę plików z konfliktami
git status
# both modified: src/ui/login/LoginActivity.kt

# 3. Rozwiązać konflikt: edytować plik, usunąć znaczniki
# 4. Dodać rozwiązany plik i zakończyć merge
git add src/ui/login/LoginActivity.kt
git merge --continue
# lub: git commit (bez --continue)

Do rozwiązywania konfliktów istnieją narzędzia: git mergetool otwiera wizualny merger (Meld, Beyond Compare, VS Code). Wielu programistów woli rozwiązywać konflikty w IDE — IntelliJ IDEA i Android Studio udostępniają wbudowane narzędzie z trójpanelowym porównaniem, które znacznie upraszcza ten proces.

Porady dotyczące rozwiązywania konfliktów: zawsze rozumiej, co robi każda strona konfliktu, nie usuwaj cudzego kodu bez zrozumienia jego logiki, a jeśli konflikt jest zbyt skomplikowany — zaangażuj autora obu gałęzi do wspólnego rozwiązania.

Merge vs Rebase: kiedy co wybrać

Wybór między Merge a Rebase — to jedna z najczęstszych decyzji architektonicznych w Git. Oba podejścia łączą zmiany, ale robią to inaczej: merge zachowuje historię rozgałęzień, rebase przepisuje historię, czyniąc ją liniową.

  • Merge — zachowuje kontekst: widać, kiedy i od której gałęzi dokonano scalania. Lepszy dla publicznych gałęzi (develop, main) i pracy zespołowej
  • Rebase — tworzy czystą liniową historię bez zbędnych merge commitów. Lepszy dla prywatnych gałęzi funkcji przed wysłaniem do przeglądu
  • Zasada: nigdy nie wykonuj rebase publicznych gałęzi, z których korzystają inni programiści

Wiele zespołów stosuje podejście hybrydowe: rebase w celu doprowadzenia gałęzi funkcji do aktualnego stanu develop (git rebase develop), a następnie merge z flagą --no-ff dla zarejestrowania scalania. Daje to czystą historię wewnątrz funkcji i informacyjne punkty scalania na poziomie develop.

Często zadawane pytania

Jaka jest różnica między merge a merge --no-ff?

Bez --no-ff Git wykonuje fast-forward merge, jeśli to możliwe — po prostu przesuwa wskaźnik gałęzi. Z --no-ff Git zawsze tworzy merge commit, zachowując informację o rozgałęzieniach. Zalecane dla gałęzi funkcyjnych w pracy zespołowej.

Co zrobić, jeśli konflikt merge jest bardzo duży?

Użyj git mergetool lub wbudowanego narzędzia IDE. Jeśli konflikt dotyczy dziesiątek plików — być może gałęzie zbyt mocno się rozeszły. W takim przypadku warto omówić z zespołem plan scalania, być może podzielić go na kilka etapów.

Czy można anulować merge?

Tak: git merge --abort anuluje merge, jeśli nie został jeszcze zakończony (konflikt). Jeśli merge już się zakończył — użyj git reset --hard HEAD~1 lub git revert -m 1 <merge-commit> dla bezpiecznego wycofania.

Czy trzeba tworzyć merge commit dla każdej funkcji?

Zalecane dla pracy zespołowej. Merge commit rejestruje fakt scalania, zawiera odniesienia do obu gałęzi i ułatwia zrozumienie historii. Dla prywatnych lub eksperymentalnych gałęzi dopuszczalny jest squash merge lub fast-forward.

Jak merge działa z plikami binarnymi?

Git nie może automatycznie scalać plików binarnych — wybiera jedną z wersji w całości. Dla plików binarnych (obrazy, .aab, .apk) zaleca się minimalizowanie równoległych zmian i używanie Git LFS dla dużych plików.

Podsumowanie

  • Merge — podstawowa operacja Git do łączenia zmian z jednej gałęzi do drugiej
  • Fast-forward — liniowe scalanie bez merge commitu, gdy nie ma rozbieżności
  • Three-way merge — tworzy merge commit z dwoma rodzicami, zachowuje kontekst
  • Squash merge — kompresuje wszystkie commity gałęzi w jeden, tracąc historię funkcji
  • Konflikty powstają przy zmianie tych samych wierszy i są rozwiązywane ręcznie
  • Merge różni się od Rebase: pierwszy zachowuje rozgałęzienia, drugi czyni historię liniową
  • Dla gałęzi publicznych zaleca się merge z --no-ff, dla prywatnych — rebase lub squash

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również