git push rejected (non-fast-forward): what it means and the safe fix
Git is protecting someone else’s work, possibly your own from another computer. The remote has commits you don’t have, and pushing would throw them away.
What “non-fast-forward” means
A push is only accepted automatically if your branch already contains everything on the remote branch, so the remote can simply move its pointer forward to your newest commit. That is a fast-forward. If someone else pushed in the meantime (or you pushed from another machine, or edited a file on the website), the histories have split:
remote: A---B---C---D (D is not on your machine)
local: A---B---C---E (E is not on the remote)
Moving the remote to E would lose D, so git stops with one of these messages:
! [rejected] main -> main (non-fast-forward)
! [rejected] main -> main (fetch first)
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.
The safe fix
- Bring in the remote commits.
git pull --rebasereplays your commits on top of theirs and keeps history in a straight line. Plaingit pullmakes a merge commit instead; both are safe. - Resolve conflicts if git asks. Edit the files, then
git addthem and rungit rebase --continue(orgit commitafter a merge).git rebase --abortputs everything back if you get lost. To compare two versions of a file side by side, the text diff tool works in your browser. - Push again.
git push.
To see what you are about to pull in first, run git fetch then git log --oneline HEAD..origin/main. If git complains about divergent branches and asks how to reconcile them, choose once with git config --global pull.rebase true (rebase) or false (merge).
When force-pushing is fine
After you rebase or amend commits you already pushed on your own feature branch, the remote still has the old versions, and a normal push is rejected by design. Then use:
git push --force-with-lease
It overwrites the remote only if it still looks the way it did when you last fetched, so it refuses if a teammate pushed in the meantime. Plain --force overwrites whatever is there. Never force-push a shared branch like main without agreeing it first. If you overwrote something by accident, the old commit is usually still in git reflog on the machine that had it.
Similar-looking rejections
| Message | What it really means |
|---|---|
protected branch hook declined / GH006 | The branch is protected; open a pull request instead of pushing to it. |
refusing to merge unrelated histories | The remote was created with its own first commit (often a README). git pull --allow-unrelated-histories joins them once. |
src refspec main does not match any | You have no commits yet, or the branch is called something else (master). Check git branch. |
Permission denied (publickey) | Not a history problem at all: the remote didn’t accept your SSH key. See Permission denied (publickey) fixed. |
pre-receive hook declined | A server-side rule rejected the push, such as a file too large or a secret detected. If it found a secret, rotate it first. |
Git saying You are in ‘detached HEAD’ state? Your commits may not be on any branch yet: see git detached HEAD before you push.
Pulling first gave you a conflict? Here is how to read and resolve it: git merge conflict markers.
Pull failing with refusing to merge unrelated histories? See unrelated histories explained.
git pull says you have divergent branches? Here is how to choose merge, rebase or fast-forward-only.
Brand-new repo and git push origin main says src refspec main does not match any? You probably have no commits yet — see src refspec main does not match any.
Related
local changes would be overwritten by merge · fatal: Authentication failed for
Questions
How do I fix “Updates were rejected because the tip of your current branch is behind”?
Run git pull --rebase (or git pull), resolve any conflicts, and then git push. The remote had commits you didn't have, and pulling brings them in first.
Should I use git push --force to fix a rejected push?
Only on a branch that is yours alone, after rebasing or amending commits you already pushed, and preferably as --force-with-lease. On a shared branch, --force deletes other people's commits.
What is the difference between --force and --force-with-lease?
--force overwrites the remote branch no matter what. --force-with-lease only does so if the remote still matches what you last fetched, so it refuses when someone else has pushed since.
What does “fetch first” mean in a git push error?
The same as non-fast-forward: the remote contains work you don't have locally. Fetch or pull it, then push again.
Published .