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