Git by Example: Three-Way Merge
Learn how Git handles divergent history using a three-way merge. This process creates a new merge commit to tie together two independent lines of development.
Code
# 1. Create a feature branch and commit
git switch -c feature-diverge
echo "Feature work" > feature.txt
git add feature.txt
git commit -m "Add feature work"
# 2. Switch back to main and make a DIFFERENT commit
git switch main
echo "Mainline work" > main.txt
git add main.txt
git commit -m "Add mainline work"
# 3. Merge the feature branch
git merge feature-diverge
# Output:
# Merge made by the 'ort' strategy.
# feature.txt | 1 +
# 1 file changed, 1 insertion(+)
# create mode 100644 feature.txt
# 4. Verify the branching history
git log --oneline --graph --all
# Output:
# * 9g8h7i (HEAD -> main) Merge branch 'feature-diverge'
# |# | * 5e6f7g (feature-diverge) Add feature work
# * | 3c4d5e Add mainline work
# |/
# * 1a2b3c Initial commitExplanation
A three-way merge is required when the history of the two branches has diverged. This means that since the feature branch was created, new commits have also been added to the main branch. In this case, a simple fast-forward is impossible because there is no single linear path that includes all changes.
Git solves this by performing a three-way comparison. It looks at three specific snapshots: the tip of the current branch (HEAD), the tip of the branch being merged, and the common ancestor of both branches. By comparing these three points, Git can intelligently combine the changes. If the changes are in different files or different parts of the same file, Git merges them automatically.
The result of a three-way merge is a special merge commit. Unlike normal commits which have one parent, a merge commit has two parents: the last commit from the main branch and the last commit from the feature branch. This commit ties the two histories together, creating a visual "diamond" shape in the commit graph.
- Required when branches have diverged
- Uses a common ancestor to calculate changes
- Creates a new merge commit with two parents
- Preserves the history of parallel development

