Three-Way Merge in Git Explained with Diagrams
In the previous blog, we learned about fast forward merge. But sometimes, Git cannot simply move the pointer forward because both branches have diverged. This is where a three-way merge comes in.
Project Setup
We start from a clean main branch with recent commits already merged.
git branch
# * main
The main branch pointer is attached to the latest commit.
All previous feature branches were deleted.
Running ls, we see that the chat feature and modifications from the previous merge are present.
Creating a Diverging Branch
Let’s create a new branch for a video chat feature:
git switch -C feature/video
Now the HEAD is pointing to feature/video.
We add some commits here:
echo "video call feature - group VC" > group_vc.txt
git add group_vc.txt
git commit -m "Add group VC feature"
echo "video call feature - 1:1 VC" > one_to_one_vc.txt
git add one_to_one_vc.txt
git commit -m "Add one-to-one VC feature"
echo "video call - update hello" >> hello.txt
git add hello.txt
git commit -m "Update hello.txt with video call info"
At this point:
feature/videohas three commits ahead ofmain.mainstill points to the earlier commit.
Making a Commit on Main
Switch back to main and add a new file:
git switch main
echo "New file on main branch" > new_file.txt
git add new_file.txt
git commit -m "Add new file on main branch"
Now both branches (main and feature/video) have diverged.
Why a Three-Way Merge is Needed
At this point, Git cannot do a fast forward merge because:
mainhas a unique commit (new_file.txt).feature/videohas its own three commits.
If Git simply moved the pointer, it would lose the new_file.txt commit.
So instead, Git performs a three-way merge.
Performing a Three-Way Merge
On the main branch, run:
git merge feature/video
Git opens your editor for a merge commit message:
Merge branch 'feature/video'
Save and exit (:wq in Vim).
A new merge commit is created which has two parents:
- The latest commit of
main. - The latest commit of
feature/video.
Visualizing the Merge
Before Merge
After Merge
Here:
- Git created M1 (merge commit).
mainnow points to this new merge commit.- History is not linear anymore — this is normal for three-way merges.
Listing and Filtering Branches
- See all branches:
git branch
- See merged branches:
git branch --merged
- See unmerged branches:
git branch --no-merged
- Filter branches by pattern (e.g., only feature branches):
git branch -l "feature/*"
This is very useful in real-world projects to separate feature branches from bugfix branches.
Summary
- Fast forward merge: moves pointer if no divergence.
- Three-way merge: required when both branches have new commits.
- Git creates a new merge commit with two parents.
- History becomes non-linear.
- Use
git branch -lto filter branches,--mergedand--no-mergedto check status.
Keep Learning 🚀
👉 Subscribe to Learning Ocean – Subscribers get coupon codes for my courses, early access to blogs and courses, and even exclusive YouTube videos.
👉 My YouTube Channel – More videos, more fun, and lots of learning!
👉 📺 Watch this topic in video form
Stay curious, keep coding, and let’s make learning fun together! 🎉