Why do I get a “fast forward rejected” when I push a second time?

Summary

A “fast forward rejected” error on a second push happens when your local branch’s history no longer matches the remote’s history. Even if you are the only developer, Git can still detect divergence when the remote branch contains commits your local branch does not—often caused by non-fast‑forward updates, rebases, or detached‑HEAD pushes you forgot happened.

Root Cause

The error occurs because Git refuses to overwrite remote history unless explicitly told to. Common underlying causes include:

  • A previous push rewrote history (e.g., via git commit --amend or git rebase)
  • A detached HEAD push created a different commit ID even if the content looked identical
  • Hooks or automation mutated commits (timestamps, metadata, filters)
  • You pulled with rebase, causing your local branch to have new commit IDs
  • Your remote branch was updated by a different clone you forgot about (CI, another machine, etc.)

The key point: Git compares commit IDs, not file content. If the commit graph differs, fast‑forward is impossible.

Why This Happens in Real Systems

Even solo developers hit this because Git’s model is based on immutable commit DAGs, not on “who changed what.”

Typical real‑world triggers:

  • Amending commits after pushing
  • Rebasing after pushing
  • Force‑pushes from another machine
  • Accidental commits on the remote (e.g., via web UI)
  • Pre‑receive hooks rewriting commits

Any operation that changes commit hashes—even if the files are identical—creates divergence.

Real-World Impact

When this happens in production environments, it can cause:

  • Blocked deployments because CI cannot fast‑forward
  • Broken automation that expects linear history
  • Confusion among developers who believe they “did nothing wrong”
  • History inconsistencies that require force‑pushes to repair

Example or Code (if necessary and relevant)

A typical scenario:

git commit --amend
git push

Then later:

git commit -m "next change"
git push

The second push fails because the amended commit changed the commit ID, making the remote history incompatible with a fast‑forward.

How Senior Engineers Fix It

Experienced engineers approach this systematically:

  • Inspect the commit graph using git log --graph --oneline --decorate
  • Verify whether history was rewritten (amend, rebase, cherry-pick)
  • Check other clones (laptop, workstation, CI) for pushes
  • Use git pull --rebase to realign history
  • Force‑push only when absolutely safe, and only after confirming no one else depends on the branch

They treat Git as a graph synchronization problem, not a file‑sync problem.

Why Juniors Miss It

Less experienced developers often:

  • Assume “I’m the only one pushing, so nothing could have changed”
  • Think Git tracks file content, not commit DAGs
  • Forget about previous rebases or amended commits
  • Don’t realize that identical content can still produce different commit IDs
  • Don’t check other machines or automation that may have pushed

They see Git as a storage system, while seniors understand it as a history‑tracking system.

If you want, I can also outline a troubleshooting checklist that helps diagnose these issues quickly.

Leave a Comment