linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Chapters
  • How it works
  • Lessons
  • Knowledge base
  • Interview prep
home/git/kb/Branches & merging/fast-forward

kb/branching ── Branches & merging ── beginner

Fast-forward merge

The simplest form of merge: Git moves the branch pointer to the new commit without creating a merge object. Possible only when the target branch has no commits of its own since the point of divergence.

view as markdownaka: ff, fast-forward-merge

When git merge feat runs on branch main, Git first checks: can it simply fast-forward main to the tip of feat?

When it is possible

When main has received no new commits since the branch was created:

before merge:
  main:  A → B
              \
  feat:        C → D
git switch main && git merge feat:
after:
  main:  A → B → C → D    ← main caught up with feat
  feat:  A → B → C → D

No merge commit is created. Git simply rewrites .git/refs/heads/main from the old SHA to the SHA of commit D.

When it is not possible

When main has at least one commit of its own since the branch was created:

main:  A → B → E
                \
feat:            C → D

Here fast-forward is not possible. A three-way merge with a merge commit is required (see merge).

Controlling the behavior

bash
git merge feat                 # fast-forward if possible, otherwise three-way
git merge --no-ff feat         # always create a merge commit,
                                # even when fast-forward is possible
git merge --ff-only feat       # fast-forward only; refuse if not possible
  • --no-ff is the strategy teams use when they want to preserve topology: "there was a feature branch here." Useful for GitFlow.
  • --ff-only guards against accidental merge commits. It works well as the default for pull: git config --global pull.ff only.

Pitfalls

  • fast-forward creates no extra commit, so git log --oneline --graph does not show that a branch existed. If the fact of branching matters for audit purposes, use --no-ff.
  • With --ff-only, if the branches have diverged Git refuses to proceed. You need to explicitly merge or rebase rather than relying on automatic behavior.
  • The default for pull has historically been different. To avoid getting unexpected merge commits, set pull.ff = only or pull.rebase = true.

§ команды

bash
git merge feat

Merge feat into the current branch; fast-forward if possible

bash
git merge --no-ff feat

Always create a merge commit, preserving topology

bash
git merge --ff-only feat

fast-forward only; refuse if branches have diverged

§ см. также

  • mergegit mergeMerges another branch into the current one. Either fast-forwards the pointer or creates a merge commit with two parents. Overlapping changes produce conflicts.
  • rebasegit rebaseRewrites the commits of a branch so they descend from a different commit. Each commit gets a new SHA; history becomes linear. Safe only on branches that no one else has seen.
  • branchBranchA branch in Git is a file inside `.git/refs/heads/` that holds the SHA of one commit. Creating, switching, and deleting branches are trivial operations because a branch contains exactly 41 bytes of data.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies