Merge
About
Merging in Git is the process of combining changes from two branches into one. It's used when we want to integrate work from a feature branch back into the main development branch (e.g., main, develop, or release/1.x) or vice versa.
Merging preserves the history of both branches and creates a new commit (called a merge commit) that ties them together.
How Merge Works in Git ?
When we run a git merge, Git looks for the common ancestor of the two branches and compares the changes made on each side from that point.
Example scenario:
mainandfeature-xboth originated from commitA.mainhas commitB.feature-xhas commitsCandD.
When we merge feature-x into main, Git:
Identifies commit
Aas the common ancestor.Applies the changes from commits
CandDonto the currentmain.Creates a new merge commit
Ewith two parents:BandD.
The resulting history looks like this:
A---B---------E (main)
\ /
C---D (feature-x)Types of Merges
1. Fast-Forward Merge
When it happens ?
A fast-forward merge occurs when the current branch has no new commits since it diverged from the branch being merged. Git doesn’t need to create a merge commit — it simply moves the pointer forward.
Before:
A---B---C---D (feature)
↑
(main)mainis currently pointing toCfeaturehas advanced toDmainhas no new commits afterC, so Git can fast-forward it toD
After:
A---B---C---D (main, feature)Git just advances the
mainpointer toD, the tip of thefeaturebranch.This results in a linear history.
No merge commit is created.
Command
git checkout main
git merge featureWhen to use ?
Feature branch is fully ahead of main with no divergence.
We want clean, simple history.
2. No Fast-Forward Merge (--no-ff)
--no-ff)When it happens ?
We use this when we want to force Git to create a merge commit, even if a fast-forward is possible. This helps preserve the context of the feature branch.
Before:
A---B---C---D (feature)
↑
(main)mainis at commitCfeatureis ahead by one commit:D
After:
A---B---C-------E (main)
\ /
D---/ (feature)Eis a merge commit with parents:CandDmainnow includes the full history of the featurefeaturestill exists (optional to delete)
Explanation
Forces a new commit
Eto indicate a merge took place.The feature branch’s existence is preserved in history.
Useful for tracking what was merged and when.
Command
git checkout main
git merge --no-ff featureWhen to use ?
We want to preserve the feature branch's identity.
Our team policy enforces explicit merge commits.
For audit or traceability reasons.
3. Three-Way Merge (Standard Merge with Divergence)
When it happens ?
Both the base branch and feature branch have diverged — i.e., each has commits the other doesn’t have.
Before:
E---F (feature)
/
A---B---C (main)Bis the common ancestormainhas commits:B → Cfeaturehas commits:B → E → F
After:
E---F
/ \
A---B---C---G (main)
↑
(merge commit)Gis the merge commit with two parents:One from
main(C)One from
feature(F)
mainnow includes changes from both branchesHistory is non-linear, but traceable
Command
git checkout main
git merge featureWhen to use ?
The branches have diverged.
We want a complete history of how changes were integrated.
Most common real-world merge scenario.
4. Octopus Merge
When it happens ?
Used when merging more than two branches at once.
Before:
C (feature1)
/
A---B
\
D (feature2)
\
E (feature3)All three feature branches (
feature1,feature2,feature3) diverged from a common base (B)They have no conflicting changes
After:
C D E
\ | /
A---B-----F (main)
↑
(merge commit)Fis the octopus merge commitHas multiple parents:
C,D,Emainnow contains all changes fromfeature1,feature2, andfeature3
Command
git merge feature1 feature2When to use ?
Automated merges with no conflicts.
Integrating multiple feature branches at once (e.g., for a release).
5. Merge with Conflicts
When it happens ?
A merge conflict occurs when two branches modify the same line in a file or delete/rename the same file differently.
Git cannot automatically decide whose change to keep, so it stops the merge and asks for manual intervention.
Before Merge:
Let’s say we have a file greeting.txt.
Content of greeting.txt on main:
Hello from Main!
Content of greeting.txt on feature:
Hello from Feature!Branch Structure:
C (feature - changes greeting.txt)
/
A---B---D (main - also changes greeting.txt)Bis the common ancestorBoth
mainandfeaturechanged the same line ingreeting.txtin different ways
Attempting Merge:
git checkout main
git merge featureGit will now stop and show a merge conflict:
✖ Conflict in greeting.txt:
greeting.txt:<<<<<<< HEAD
Hello from Main!
=======
Hello from Feature!
>>>>>>> featureHEADis our current branch (main)featureis the incoming branchWe must choose which change to keep (or both)
Resolving the Conflict:
We manually edit the file, for example:
Hello from Main and Feature!Then:
git add greeting.txt
git commitGit will now complete the merge by creating a merge commit.
After Merge:
C
/
A---B---D---E (main)
\ /
(merge commit with conflict resolved)Eis the merge commitIt has two parents:
D(main) andC(feature)greeting.txtnow contains the manually resolved content
Merge Strategy Options
Git also offers internal merge strategies used behind the scenes:
recursive (default)
Standard three-way merge; handles most cases
resolve
Simple strategy, limited capabilities
ours
Keeps the current branch’s changes only
theirs
Keeps the incoming branch’s changes (used in rebasing with strategy options)
octopus
Used when merging more than two branches
Example:
git merge --strategy=recursive featureComparison
Fast-Forward
No
Yes
No (no divergence)
Simple merges, clean linear history
No Fast-Forward
Yes
No
Yes
Preserve feature branch history
Three-Way Merge
Yes
No
Yes
Diverged branches, active collaboration
Octopus Merge
Yes (single commit)
No
No (fails on conflict)
Merge multiple branches at once
Merge with Conflicts
Yes
No
Yes (manual resolution)
When overlapping changes cause conflicts
When to Use Merge ?
Use merge when:
We want to preserve the full history of both branches.
Our team prefers non-destructive history.
We are working on long-running branches (e.g.,
release/1.x,develop, etc.).We want to use GitLab Merge Requests or GitHub Pull Requests and show clear integration points.
Merge vs Rebase
History
Preserved, non-linear
Linearized, rewritten
Merge commit
Yes
No (unless explicitly created)
Conflict handling
All at once
One commit at a time
Use case
Collaborative workflows, history trace
Clean history, private feature branches
Practical Use Cases
1. Standard Feature Branch Merge into Main Branch
Problem: We completed a feature in a separate branch (feature/login). Now we want to bring that code into the main integration branch (develop or main), while preserving commit history.
Why Use Merge: Merging retains the complete branch history and clearly shows that a feature was developed independently and then integrated.
Command:
git checkout develop
git merge feature/loginEffect:
Creates a new merge commit.
Keeps all commits from
feature/login.Shows a clear branch-and-merge structure.
2. Bugfix Branch Merged Back Into Production
Problem: We created a hotfix branch (hotfix/issue-404) from main to quickly fix a production bug. Now the fix is done and tested.
Why Use Merge: We want the fix to be merged back while preserving the commit structure and making it traceable.
Command:
git checkout main
git merge hotfix/issue-404Effect:
Keeps the hotfix history visible.
Avoids altering existing commits (unlike rebase).
3. Combining Two Active Feature Branches
Problem: Two related features are being developed in separate branches (feature/auth and feature/dashboard), and now we need to test them together locally before integrating into main.
Why Use Merge: We want to combine branches without changing their history. Merging is safe and non-destructive.
Command:
git checkout feature/auth
git merge feature/dashboardEffect: We can test how both features behave together. If something breaks, history is untouched and reversible.
4. Bringing Develop Changes into Feature Branch
Problem: We are working on a long-lived branch (feature/analytics), and the develop branch has changed significantly (other features, refactoring, etc.). We need to sync.
Why Use Merge:
We want to bring changes from develop into our branch to test compatibility and resolve conflicts without rewriting our feature’s history.
Command:
git checkout feature/analytics
git merge developEffect:
Resolves conflicts now instead of during the final merge.
Preserves our work’s history.
Keeps commits in their original sequence.
5. Merging for Collaboration Between Teammates
Problem: Two developers work on the same branch locally and need to sync up regularly without rebasing over each other’s history.
Why Use Merge: Merging is safe in shared branches. It doesn’t force history rewrites, which would create confusion or conflicts in shared repos.
Command:
git pull --no-rebase(Performs a fetch + merge. Use --no-rebase to explicitly avoid rebasing.)
Effect:
Maintains all commit history.
Preserves collaborative workflows.
Last updated