What this error means
You see this when Git is asked to fast‑forward only (e.g., git pull --ff-only or git merge --ff-only) but your branch has diverged from its upstream. A fast‑forward is possible only if your branch tip is an ancestor of the target. When both sides have new commits, Git would need a merge commit or a rebase, so it aborts.
Common triggers:
git pull --ff-onlyon a branch with local commits while the remote also advanced.git merge --ff-only origin/mainwhen your branch andorigin/mainboth have new commits.- Submodules updated with
--ff-onlywhere the recorded commit cannot be fast‑forwarded.
Quickstart (choose one)
- Keep linear history (recommended):
git fetchthengit rebase origin/main
- Allow a merge commit:
git fetchthengit merge origin/main
- Update config to prefer rebase on pull:
git config --global pull.rebase true
Minimal working example (reproduce and fix)
# Setup a bare repo and two clones
mkdir ff-demo && cd ff-demo
git init --bare origin.git
git clone origin.git alice
git clone origin.git bob
# Create main and push initial commit from alice
cd alice
git switch -c main
printf "hello\n" > file.txt
git add file.txt
git commit -m "alice: initial"
git push -u origin main
# Bob pulls and adds a commit
cd ../bob
git switch -c main # tracks origin/main automatically
printf "bob line\n" >> file.txt
git commit -am "bob: change"
git push
# Alice adds her own commit locally
cd ../alice
printf "alice line\n" >> file.txt
git commit -am "alice: change"
# This fast-forward-only pull will now fail
git pull --ff-only # fatal: not possible to fast-forward, aborting
# Fix option 1: rebase for linear history
git fetch
git rebase origin/main
# Resolve any conflicts if prompted, then continue
# After successful rebase, push
git push
# Alternatively, fix option 2: allow a merge commit instead
# (reset back one commit to redo the scenario)
# git reset --hard HEAD~1
# git fetch
# git merge origin/main
# git push
Why it happens
- Your branch has commits A..B.
- The upstream branch has commits C..D not present locally.
--ff-onlyrefuses to create a merge commit. Since neither side is an ancestor, fast‑forward is impossible, so Git aborts.
Resolution paths
- Rebase your work onto the upstream (linear history)
- Save or stash local changes (if any):
git stash push -uor use--autostashbelow.
- Fetch latest remote:
git fetch
- Rebase onto the upstream tip:
git rebase origin/main
- Resolve conflicts if shown, then:
git rebase --continue
- Push updated commits:
git push(may need--force-with-leaseif you had pushed the old commits already).
Tip: git pull --rebase --autostash combines fetch + rebase and stashes dirty work.
- Merge the upstream into your branch (allow merge commit)
- Fetch latest remote:
git fetch
- Merge remote branch:
git merge origin/main
- Resolve conflicts, commit the merge if needed.
- Push:
git push
- Discard local divergence (dangerous; only if local commits aren’t needed)
- Hard reset to the upstream:
git fetchgit reset --hard origin/main
- This deletes local commits from the branch tip; ensure they are truly disposable.
- Configure your default pull strategy
- Always rebase on pull:
git config --global pull.rebase true
- Always allow merge commits on pull:
git config --global pull.ff false
- Always require fast‑forward (current behavior that triggered the error):
git config --global pull.ff only
Per‑repo versions: drop --global and run in the repo.
Handling conflicts during rebase or merge
- When conflicts occur, Git stops and marks files as conflicted.
- Use your diff tool to fix them, then:
- Rebase:
git add <file>,git rebase --continue - Merge:
git add <file>,git commit(if Git didn’t auto‑create the merge commit)
- Rebase:
- To abort:
- Rebase:
git rebase --abort - Merge:
git merge --abort
- Rebase:
Special cases
- Submodules:
git submodule update --ff-onlycan fail similarly. Usegit submodule update --mergeor update the recorded submodule commit in the superproject, then commit. - Protected branches: After a rebase, you may need
--force-with-leaseto push rewritten history. Some servers disallow this on protected branches; open a PR instead.
Pitfalls
- Rebasing shared branches: Rewriting history after others pulled your commits forces them to reconcile. Prefer merging in that case.
- Using
--forceinstead of--force-with-lease:--force-with-leaseprotects others’ work by refusing to overwrite unexpected remote tips. - Dirty working tree: Pulling with local uncommitted changes can fail or complicate rebases. Use
--autostashor stash manually. - Wrong upstream: Ensure your branch tracks the intended remote branch:
git branch -vv- Set upstream:
git branch --set-upstream-to origin/main
Performance notes
- Fetch first:
git fetchdecouples network from local operations, making rebase/merge faster and more predictable. - Large histories: Rebases work only on your local commits; they are usually fast. Merges can examine more history but are still cheap locally.
- Minimize conflict churn: Enable conflict reuse to speed repeated merges:
git config --global rerere.enabled true
- Shallow clones reduce network time:
git clone --depth 50if full history isn’t needed. - Keep repos healthy:
git gc --aggressiveis rarely necessary; prefergit gcand pruning stale refs withgit fetch --prune.
FAQ
Why does
git pull --ff-onlyfail butgit pull --rebaseworks?- Rebase rewrites your local commits on top of upstream, avoiding a merge commit. Fast‑forward‑only refuses non‑fast‑forward updates.
Is rebase safe?
- Yes for local/unshared commits. Avoid rebasing commits that others already pulled unless coordinated.
When should I choose merge over rebase?
- When preserving exact history or when the branch is shared and you want to avoid history rewrites.
Do I need to force push after rebasing?
- Only if you had previously pushed the old commits. Use
git push --force-with-lease.
- Only if you had previously pushed the old commits. Use
Can I make this error go away permanently?
- Decide your policy: set
pull.rebase true(linear history) orpull.ff false(allow merges) sogit pullwon’t abort on divergence.
- Decide your policy: set