git push rejected (non-fast-forward)
The remote branch has commits you do not have. Integrate them with pull or rebase, then push — do not force over other people's work.
What happened
You ran git push and Git refused to update the remote branch. The output marks the ref with ! and the word rejected.
$ git push origin main To github.com:mainframe-learner/mp-batch-jobs.git ! [rejected] main -> main (fetch first) error: failed to push some refs to 'github.com:mainframe-learner/mp-batch-jobs.git' hint: Updates were rejected because the remote contains work that you do not hint: have locally.
What it means
A push is a fast-forward when your new commit descends from the commit the remote branch points to now. If someone else pushed in the meantime, the remote has commits you lack. Accepting your push would drop them from the branch's history, so Git refuses by default.
In the push output, ! marks a ref that was not updated. rejected means your Git never sent the update, usually because it is not a fast-forward. remote rejected means the server refused it — for example because of a hook, branch protection, or a setting such as receive.denyNonFastForwards.
Typical causes
- A teammate pushed to the same branch since your last fetch or pull.
- You amended or rebased commits that were already pushed, so your history now differs from the remote.
- A CI job or bot committed to the branch (version bumps, generated files).
Symptoms
- Push fails; your commits stay local.
git statusshows your branch and its upstream have diverged after agit fetch.
Where to look
- The push output: the reason in brackets and whether it says rejected or remote rejected.
git fetchthengit log --oneline main..origin/mainto see the commits you are missing.- The repository's branch protection settings on GitHub if it was a remote rejection.
How to diagnose
- Run
git fetchto update your view of the remote. - Compare local and remote with
git log --oneline --graph --allor the two-dot ranges above. - Decide: are the remote commits someone else's real work (integrate them) or your own old version of rewritten history?
How to fix
- Integrate by merging:
git pull, resolve any conflicts, thengit push. - Or integrate by rebasing:
git pull --rebase, resolve conflicts, thengit push— this keeps a straight history. - Only if you intentionally rewrote your own branch and nobody else uses it:
git push --force-with-lease. It overwrites the remote only if it still points where your remote-tracking branch says, so it will not silently delete commits you have not seen.
How to prevent
- Work on your own feature branch and merge through a pull request.
- Pull (or fetch and rebase) before starting work and before pushing.
- Protect
mainso direct and forced pushes are blocked.
Production considerations
Interview question
Your push is rejected as non-fast-forward. How do you fix it?
Stuck on something else?
Ask the community or search the full course.