← Git

Branches

What is a merge and what is the difference between a fast-forward and a merge commit?

Show answer — try answering out loud first

A merge integrates the changes from one branch into another. If the target branch hasn't advanced since the other one was created, Git does a fast-forward: it just moves the pointer forward, without creating a new commit. If both branches advanced separately, Git creates a merge commit that joins the two histories and has two parents.

You worked on a feature branch and now you want to bring those changes into main. You stand on main and run git merge feature. There are two scenarios:

  • Fast-forward: main didn't receive new commits while you were working on feature. Since the history is linear, Git simply advances the pointer of main up to the last commit of feature. No merge commit is created.
  • Merge commit (three-way merge): both main and feature received different commits. Git can't just advance the pointer, so it creates a special merge commit with two parents (the last one of each branch) to join both histories. This is where conflicts can appear if the two branches touched the same lines.
# I'm on feature and I want to integrate it into main
git switch main
git merge feature

# Fast-forward case (main didn't advance):
# Output: Updating 1a2b3c4..5d6e7f8
#         Fast-forward
# No new commit is created, the pointer just moves forward

# Merge commit case (both branches advanced):
# Output: Merge made by the 'ort' strategy.
# A merge commit with two parents is created

# ALWAYS force a merge commit, even if a fast-forward is possible
git merge --no-ff feature
# Useful to leave a record in the history that a branch existed

# After merging, delete the branch
git branch -d feature

Believing that a merge always creates a merge commit. No: if it's a fast-forward, no commit is created, only the pointer moves, and the history stays linear. Another mistake is forgetting that the merge is run from the target branch: you have to be on main (or wherever you want to integrate) and merge the other branch into it.

"A merge integrates the changes from one branch into another. I stand on the target branch, for example main, and run git merge feature. If main didn't advance since feature branched off, Git does a fast-forward: it just moves the pointer forward, without a new commit. If both branches advanced separately, it creates a merge commit with two parents to join the histories, and that's where conflicts can appear. Sometimes I use --no-ff to force the merge commit and leave a record that there was a branch."

Quick challenge

You created feature from main, made 2 commits on feature, and main didn't change anything in the meantime. You run git merge feature from main. Is a merge commit created?

Show answer

No. Since main didn't advance, the history is linear and Git does a fast-forward: it simply advances the main pointer up to the last commit of feature, without creating any merge commit. If you wanted to force a merge commit anyway, you would use git merge --no-ff feature.