PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Git course #3 – branching and merge: strategies, conflicts, fast-forward

by Henryk Tews / Sunday, 10 May 2026 / Published in Bez kategorii

The question “merge or rebase?” is one of the most common in Git-using teams. Both strategies achieve the same result – integrating changes – but produce completely different history. There is no single right answer, there is context. I show when to use each, how conflicts work, and why fast-forward is not the same as “no merge commit”.

Three merge strategies

Fast-forward

Possible when the target branch has not diverged since the feature branch was created. Git simply moves the pointer – no merge commit is created.

# Fast-forward is the default when possible
git merge feature/new-endpoint

# Force no fast-forward (always create a merge commit)
git merge --no-ff feature/new-endpoint

# Check if FF is possible before merge
git merge-base --is-ancestor main feature/new-endpoint
echo $?  # 0 = yes, 1 = no

Merge commit

Creates a new commit with two parents. Preserves full history – you can see when the branch was created and when it returned. Preferred in Git Flow for merges to main/develop.

git checkout main
git merge --no-ff feature/order-export

# Merge commit message
# Merge branch 'feature/order-export'
#
# * feat(export): add CSV export for orders
# * feat(export): add PDF export for orders
# * test(export): add unit tests for ExportService

Rebase before merge

The feature branch is rebased onto the current main, then fast-forward merged. History looks linear – as if the feature was developed on the current version of main.

git checkout feature/order-export
git rebase main          # move commits to the tip of main
git checkout main
git merge feature/order-export  # fast-forward

Conflicts – how to resolve them

# During merge/rebase Git stops on conflict:
# CONFLICT (content): Merge conflict in src/Model/OrderService.php

# Check what is in conflict
git status
git diff --check

# The conflicted file contains markers:
# <<<<<<< HEAD
# $this->calculateTax($order);
# =======
# $this->calculateVat($order, $storeId);
# >>>>>>> feature/tax-refactor

# Resolve manually, remove markers, then:
git add src/Model/OrderService.php
git merge --continue    # or git rebase --continue

# Abort merge/rebase
git merge --abort
git rebase --abort

Conflict resolution tools

# Built-in tool (opens 3-panel view)
git mergetool

# Configure tool
git config --global merge.tool vimdiff
git config --global merge.tool phpstorm

# PhpStorm resolves conflicts conveniently via File | Git | Resolve Conflicts

When merge, when rebase

Situation Strategy Reason
Feature branch to main (Git Flow) –no-ff merge Visible feature history
Update feature with main rebase Linear history, simpler conflicts
Hotfix on main fast-forward Simple change, no noise
Squash before PR merge squash + merge One commit per PR
Public branch (shared) merge NEVER rebase Rebase rewrites SHAs

Octopus merge – merging multiple branches

# Merge multiple branches at once (octopus merge)
git merge feature-a feature-b feature-c

# Useful when merging independent feature branches
# Git requires no conflicts between them

Summary

Merge commit preserves branching history but “pollutes” the log with merge commits. Rebase creates linear history but rewrites SHAs – never use it on public branches. In practice: rebase to update a feature branch, –no-ff merge to integrate to the main branch. Next post: remote work – remote, fetch vs pull, force-with-lease.

About Henryk Tews

What you can read next

Git course #5 – team workflow: Git Flow, trunk-based, PR, code review
Git course #6 – hooks and automation: pre-commit, PHPStan, commit-msg, DDEV
Git course #7 – debugging and rescue: bisect, reflog, reset vs revert

© 2026 Created by

TOP
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Always active
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}