Three-Way Merge
When both branches have new commits since they diverged, Git cannot fast-forward. It must perform a three-way merge which combines the changes from both sides and records the result as a new merge commit. This is the “normal” merge people are usually picturing when they say merge.
The setup
Both branches moved
A───B───C───F ◀── main (HEAD)
\
D───E ◀── feature-x
A, B, C = shared ancestors
F = commit added to main after the branch happened
D, E = commits added to feature-xWhy “three-way”?
Git compares three snapshots:
The common ancestor — the latest commit reachable from both branches. Here that is
C.The tip of the current branch —
Fonmain.The tip of the branch being merged in —
Eonfeature-x.
For each file, Git computes the changes made on each side relative to the ancestor, and combines them. If the same lines were changed in both places, that is a conflict.
The merge command
git switch main git merge feature-x # Merge made by the 'recursive' strategy. # (your editor opens for the merge commit message)
The result
A merge commit appears
A───B───C───F───M ◀── main
\ /
D───E───┘ ◀── feature-xM has two parents (F and E). That is what makes it a merge commit. git log --graph will draw the diamond shape so you can see it.
Inspecting a merge commit
git show M # commit ... # Merge: F E # Author: ... # Date: ... # # Merge branch 'feature-x' into main # Each parent git log M^1 # first parent (the branch you were on — main) git log M^2 # second parent (the branch you merged in — feature-x)
Recursive strategy
Git’s default merge strategy is called recursive. It finds the merge base (common ancestor), computes diffs, and combines them. If multiple merge bases exist, recursive merges them first to produce one virtual merge base — that is the “recursive” part.
What changes go into M?
All changes that one side made that the other side did not — applied automatically.
Changes both sides made in the same way — kept once.
Changes both sides made in conflicting ways — left in the file with conflict markers for you to resolve.
Authorship and date
The author of the merge commit is whoever ran git merge — not the original authors of the individual commits. The original commits keep their own author info; the merge commit is just a join point.
Editing the merge commit message
Two options
# Inline git merge feature-x -m "Merge feature-x: add OAuth login" # Editor (better for descriptive merges) git merge feature-x # (your editor opens with a default message — edit to taste)
Three-way merge vs squash vs rebase
Three-way merge — preserves both branches in history. Most accurate record of what happened.
Squash — collapses the whole branch into one commit on main, then FFs. No branch history.
Rebase — rewrites the source commits onto main so that the merge can fast-forward. Linear history, but the original commit hashes are different.
The recursive algorithm in plain English
Find the latest commit reachable from both branches → the merge base.
For each file: produce two diffs (base vs A and base vs B).
Apply both diffs to the base.
Non-overlapping changes combine cleanly.
Overlapping changes are marked as conflicts.
Output: a new tree (merged files) and a commit with two parents.
git log main..feature-x --oneline and git log feature-x..main --oneline. Now you know exactly what each side has that the other does not — and you can predict where conflicts might appear.