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:
main
andfeature-x
both originated from commitA
.main
has commitB
.feature-x
has commitsC
andD
.
When we merge feature-x
into main
, Git:
Identifies commit
A
as the common ancestor.Applies the changes from commits
C
andD
onto the currentmain
.Creates a new merge commit
E
with two parents:B
andD
.
The resulting history looks like this:
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:
main
is currently pointing toC
feature
has advanced toD
main
has no new commits afterC
, so Git can fast-forward it toD
After:
Git just advances the
main
pointer toD
, the tip of thefeature
branch.This results in a linear history.
No merge commit is created.
Command
When 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:
main
is at commitC
feature
is ahead by one commit:D
After:
E
is a merge commit with parents:C
andD
main
now includes the full history of the featurefeature
still exists (optional to delete)
Explanation
Forces a new commit
E
to indicate a merge took place.The feature branch’s existence is preserved in history.
Useful for tracking what was merged and when.
Command
When 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:
B
is the common ancestormain
has commits:B → C
feature
has commits:B → E → F
After:
G
is the merge commit with two parents:One from
main
(C
)One from
feature
(F
)
main
now includes changes from both branchesHistory is non-linear, but traceable
Command
When 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:
All three feature branches (
feature1
,feature2
,feature3
) diverged from a common base (B
)They have no conflicting changes
After:
F
is the octopus merge commitHas multiple parents:
C
,D
,E
main
now contains all changes fromfeature1
,feature2
, andfeature3
Command
When 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
.
Branch Structure:
B
is the common ancestorBoth
main
andfeature
changed the same line ingreeting.txt
in different ways
Attempting Merge:
Git will now stop and show a merge conflict:
✖ Conflict in greeting.txt
:
greeting.txt
:HEAD
is our current branch (main
)feature
is the incoming branchWe must choose which change to keep (or both)
Resolving the Conflict:
We manually edit the file, for example:
Then:
Git will now complete the merge by creating a merge commit.
After Merge:
E
is the merge commitIt has two parents:
D
(main) andC
(feature)greeting.txt
now 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:
Comparison
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:
Effect:
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:
Effect:
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:
Effect: 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:
Effect:
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:
(Performs a fetch + merge. Use --no-rebase
to explicitly avoid rebasing.)
Effect:
Maintains all commit history.
Preserves collaborative workflows.
Last updated
Was this helpful?