Introduction

After a force push to the main branch, other developers' subsequent pushes are rejected with a non-fast-forward error because their local history diverges from the rewritten remote history:

bash
git push origin main
# To github.com:org/repo.git
#  ! [rejected]        main -> main (non-fast-forward)
# error: failed to push some refs to 'github.com:org/repo.git'
# hint: Updates were rejected because the tip of your current branch is behind
# hint: its remote counterpart.

This is a common and disruptive issue for teams when someone force pushes to a shared branch.

Symptoms

  • Push rejected with "non-fast-forward" error
  • Local branch history diverges from remote
  • Pull/rebase creates messy merge commits or conflicts
  • Team members lose their commits if they force push in response
  • CI/CD pipelines fail due to unexpected branch state

Common Causes

  • Someone ran git push --force origin main rewriting shared history
  • Force push after an interactive rebase or commit amend on main
  • Developer confused about which branch they are on
  • No branch protection rules preventing force pushes to main
  • Team members pulled before the force push and now have divergent history

Step-by-Step Fix

  1. 1.Fetch the current remote state:
  2. 2.```bash
  3. 3.git fetch origin
  4. 4.`
  5. 5.Check what commits you have that the remote does not:
  6. 6.```bash
  7. 7.git log origin/main..HEAD --oneline
  8. 8.# Shows your commits that are not on the remote
  9. 9.`
  10. 10.Rebase your work onto the new remote history:
  11. 11.```bash
  12. 12.git rebase origin/main
  13. 13.# Resolve any conflicts, then:
  14. 14.git push origin main
  15. 15.`
  16. 16.If you cannot rebase cleanly, create a backup branch first:
  17. 17.```bash
  18. 18.git branch my-work-backup
  19. 19.git reset --hard origin/main
  20. 20.git cherry-pick <your-commit-hashes>
  21. 21.git push origin main
  22. 22.`
  23. 23.Prevent future occurrences with branch protection. On GitHub:
  24. 24.- Go to Settings > Branches > Add rule
  25. 25.- Pattern: main
  26. 26.- Check "Require pull request reviews before merging"
  27. 27.- Check "Restrict who can push to matching branches"
  28. 28.- Enable "Include administrators"
  29. 29.**Use --force-with-lease instead of --force**:
  30. 30.```bash
  31. 31.git push --force-with-lease origin feature-branch
  32. 32.`
  33. 33.This only force pushes if the remote branch has not changed since your last fetch, preventing accidental overwrites of others' work.

Prevention

  • Enable branch protection rules on all shared branches (main, develop, release)
  • Use --force-with-lease instead of --force for all force pushes
  • Never force push to shared branches - only to personal feature branches
  • Communicate force push plans to the team via Slack or team chat
  • Use git push --force-if-includes (Git 2.30+) for an additional safety check
  • Set up server-side hooks to reject force pushes to protected branches
  • Train all team members on the dangers of force pushing to shared branches
  • Use git config push.default current to prevent accidentally pushing the wrong branch