
Module 4 Lesson 4: Fast-forward vs three-way merges
Not all merges are the same. Learn the difference between a simple 'Fast-Forward' and the more complex 'Merge Commit' (Three-Way Merge) and when to use each.
Module 4 Lesson 4: Fast-forward vs three-way merges
When you run git merge, you might see a message saying "Fast-forward" or you might be asked to write a "Merge commit message." Why the difference?
Understanding these two types of merges helps you control how your project history looks.
1. Fast-Forward Merge
A fast-forward merge happens when the target branch hasn't changed since you created your feature branch.
Git doesn't need to do any complex calculations. It simply moves the main pointer forward to the same commit as your feature branch.
Characteristics:
- No new commit is created.
- The history looks like a straight line.
- It is clean and simple.
graph LR
subgraph "Before Merge"
C1 --> C2[main]
C2 --> F1
F1 --> F2[feature]
end
subgraph "After Fast-Forward"
C1_A --> C2_A
C2_A --> F1_A
F1_A --> F2_A["main / feature"]
end
2. Three-Way Merge (Merge Commit)
A three-way merge happens when both branches have new commits since they diverged.
Git must compare three things:
- The common ancestor.
- The latest commit in
main. - The latest commit in your
feature.
Git then creates a new commit (called a "Merge Commit") that has two parents.
Characteristics:
- A new "Merge Commit" appears in the log.
- History has a "diamond" or "fork" shape.
- Preserves the fact that a feature was developed separately.
3. Which one is better?
The "Clean History" View (Fast-Forward Only)
Some teams prefer a perfectly straight line of history. They use a technique called Rebase (Module 6) to ensure every merge is a fast-forward.
The "Traceable History" View (Merge Commits)
Other teams want to see when a specific branch was merged. They even force Git to create a merge commit even if a fast-forward is possible:
git merge --no-ff feature-a
graph TD
Ancestor["Commit 1"] --> MainCommit["Commit 2 (main)"]
Ancestor --> FeatureCommit["Commit A (feature)"]
MainCommit --> MergeCommit["Merge Commit (3-way)"]
FeatureCommit --> MergeCommit
style MergeCommit fill:#f9f
Lesson Exercise
Goal: Force a non-fast-forward merge.
- Go to your
mainbranch and create a new branchquick-fix. - Add a commit to
quick-fix. - Switch back to
main. Do not add any commits tomain. - Merge
quick-fixintomainusinggit merge --no-ff quick-fix. - Run
git log --oneline --graph. - Do you see a new commit starting with "Merge branch..."? Even though Git could have just fast-forwarded the pointer?
Observation: By using --no-ff, you made it clear in the history that the quick-fix branch existed and was integrated at this specific point.
Summary
In this lesson, we established:
- Fast-Forward: Just moves the pointer (straight-line history).
- Three-Way Merge: Creates a merge commit (branching history).
--no-ffallows you to force a merge commit even when a fast-forward is possible.
Next Lesson: Everything we’ve done so far assumes Git could handle the merge automatically. But what if two people change the same line of the same file? Welcome to Lesson 5: Handling merge conflicts.