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/video has three commits ahead of main.
  • main still 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:

  • main has a unique commit (new_file.txt).
  • feature/video has 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).
  • main now 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 -l to filter branches, --merged and --no-merged to 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! 🎉