Merge Types

Updated

October 30, 2026

Merge Types: Fast-Forward, Recursive, and Octopus

After this page you can name the three merge shapes Git actually writes.

Fast-forward

main is an ancestor of feat/ping-json. Merging can just slide main forward. No new commit.

A ← B ← C                 main
          ← D ← E         feat/ping-json

# after git switch main && git merge feat/ping-json

A ← B ← C ← D ← E         main, feat/ping-json
git switch main
git merge feat/ping-json

git log shows a straight line. git merge --no-ff forces a merge commit even when a fast-forward is possible (Git Flow likes that; trunk-based usually does not).

Recursive (two parents)

The branches diverged. Git writes a merge commit with two parents.

A ← B ← C ← M             main
     ↑      ↑
     D ← E                feat/ping-json

The default strategy for two heads is ort (the current “recursive” replacement). You rarely pass -s. Git finds a merge base (common ancestor), diffs both sides against it, and applies both diffs to the base.

git switch main
git merge feat/ping-json -m "merge feat/ping-json"
git log --oneline --graph --decorate

Octopus (three or more parents)

git merge topic-a topic-b topic-c

One merge commit with several parents. Git only does this when there are no overlapping conflicts. If two topics touch the same hunk, octopus refuses; merge them pairwise instead. You will almost never need octopus on desk-api. Know the name so git log --graph with a commit that has three parents is not a mystery.

 A ← B ← C ← M          main     M has three parents
      ↑  ↑   ↑
      D  E   F          three topic tips

See the parents

git cat-file -p HEAD
git rev-parse HEAD^1 HEAD^2

HEAD^1 is the first parent (the branch you had checked out). HEAD^2 is what you merged in.

Abort

git merge --abort

Returns the three trees to the pre-merge state while a merge is in progress (MERGE_HEAD exists). After the merge commit exists, abort is too late; git reset (chapter 7) or git revert -m 1 (chapter 10).