Fast-Forward and Other Merge Strategies

15.1 What Is a Fast-Forward Merge?

A fast-forward merge occurs when the target branch has not diverged from the source branch.

Example history before merge:
1main: A — B 2 \ 3 C — D (feature)

Since main has no new commits after B, Git simply moves the main pointer forward:
1git checkout main 2git merge feature 3# Output: Fast-forward

Result:
1main → A — B — C — D

No merge commit is created.

When to use fast-forward:
Small feature branches
Solo development
When a simple, linear history is preferred

15.2 The --no-ff (No Fast-Forward) Merge

A non-fast-forward merge forces Git to create a merge commit even if a fast-forward was possible.
1git merge --no-ff feature

Result history:
1A — B — C — D — M 2 ↖ feature

Why use --no-ff ?
Preserves the idea of a branch in history
Makes it clear what work belonged to which feature
Helpful in team environments

Many teams use:
1git merge --no-ff feature-branch
as a standard practice.

15.3 The 3-Way Merge (Most Common Case)

Used when branches have diverged, i.e., both have new commits.

History example:
1main: A — B — C 2 \ 3feature: D — E

Command:
1git merge feature

Git finds:
Base commit (B)
Current branch commit (C)
Branch being merged commit (E)

It combines all three → creates a merge commit.
3-way merges preserve full history and are the standard merge type in shared repos.

15.4 Squash Merge

A squash merge compresses all commits of a branch into one.

1git merge --squash feature 2git commit -m "Add login feature"

Result:
1A — B — C — D (single combined commit)

Why squash?
Simplifies messy or experimental commit history
Keeps main very clean

It is ideal for:
Early stage prototypes
Inexperienced contributors
Large PRs broken into many small commits

15.5 Merge Strategy Options (--strategy)

Git merges can be influenced using strategies.

5.1 Recursive Strategy (default)

The standard for merging two branches.
1git merge -s recursive feature

5.2 Ours Strategy

Keeps your branch's changes, ignores the incoming branch.
1git merge -s ours feature
Useful for:
Marking a branch as merged
Keeping history but discarding code

5.3 Octopus Strategy

For merging multiple branches at once.
1git merge branch1 branch2 branch3
Used mainly in large automated integration flows.

15.6 Choosing the Right Merge Behavior

Your decision depends on your team's workflow:

Fast-Forward (Default)
Clean linear history
Simple and useful for solo developers

No Fast-Forward
Keeps feature branches visible in history
Enables better code review tracking

Squash
Great for tidying up messy branches
Best for feature branches with many commits

3-Way Merge
Safe, preserves all contributions
Standard in teams with parallel work

15.7 Best Practices

Fast-forward for small or personal branches
No-ff for major features to preserve branch structure
Squash for cleanup
Avoid rewriting history on shared branches
Keep branches short-lived to avoid complex merges

15.8 Key Takeaways

Fast-forward moves the branch pointer directly—no merge commit.
No-fast-forward creates a merge commit, even if not needed.
3-way merge handles diverged branches with a new commit.
Squash merge compresses all commits into one.
Merge strategies (recursive, ours, octopus) offer additional control.
Choose merge type based on whether you want a clean history, explicit feature boundaries, or simplified commits.