git push rejected — "failed to push some refs" (non-fast-forward)
Filed under Deployment failures
The remote repository has commits your local copy does not — someone or something pushed first — and git will not let you overwrite them.
Fastest route
Give your AI this prompt
Copy it, replace the bracketed part with your error, and send it.
Preview the prompt
My git push was rejected. The full output is: [paste the full push output, including the hint lines]. Context: this repo is also connected to [my AI builder / just me / me and a teammate], and the branch is [branch name]. Please: 1) explain in plain English why the push was rejected and confirm that none of my commits are lost, 2) give me the exact commands to integrate the remote changes using pull --rebase and push again, 3) if the rebase stops on a conflict, show me how to read the conflict markers in the affected file and what to do at each step, including how to abort safely if I get lost. Constraints: do not tell me to use git push --force or --force-with-lease, do not suggest deleting and re-cloning the repository, and warn me before any command that could discard work.
Fix it yourself
Follow the repair
- Read the hint lines under the error. Git explains itself better than its reputation suggests. Under "failed to push some refs" you will find the rejection, the branch name, the words "non-fast-forward", and a hint saying the tip of your branch is behind the remote and to integrate the remote changes before pushing again. Take it at its word — that hint is the entire treatment plan, and steps 2 and 3 are just carrying it out.
- Pull with rebase, then push again. Run:
The pull fetches the remote's commits and replays your local commits on top of them, one by one, as if you had written them after seeing the other work. The histories join into a single straight line, the push now continues from the true tip, and git accepts it. Nine times out of ten, you are done here, in under a minute.git pull --rebase git push - If it stops on a conflict, resolve it deliberately. Sometimes both sides changed the same lines, and the rebase pauses to ask a human. Git marks the conflicted spots in the file between
<<<<<<<and>>>>>>>markers. Edit each marked section into the single correct combined result — delete the markers and the version that should not survive — then:
Repeat for each stop until the rebase reports success, thengit add the-file-you-fixed git rebase --continuegit push. If you get lost mid-conflict,git rebase --abortreturns you safely to where you started — nothing about this is irreversible. - Work out who else is writing to this repository. Worth sixty seconds, because it predicts the next occurrence. If you build with a browser-based AI tool connected to this repo, that is your second writer — it pushes as it works, and your local copy goes stale during every session. A README edited on the website counts too, as does a forgotten second clone. Knowing the other writer turns this error from a recurring ambush into an expected handshake.
- Do not reach for --force. Search results will offer
git push --forceas the quick fix. Understand what it does: it orders the remote to replace its history with yours, deleting the commits you have not seen — quite possibly the builder's latest feature or your own work from another machine. That is the only move in this whole situation that destroys anything. If you ever conclude you truly must rewrite a branch that only you use,--force-with-leaseat least refuses when the remote has changed since you last looked. - Make pulling a session habit. Two copies that sync often rarely drift far enough to conflict badly. Run
git pullwhen you sit down, before making changes — and make it a ritual after every session with a browser-based builder, before you touch the local copy. The rebase then combines a commit or two instead of a day's divergent work, and "failed to push some refs" becomes a rarity rather than a routine.
Why this happensOptional explanation
Think of the remote repository as a shared document with a strict rule: you can only add your pages to the end of the version you have read. When you push, git compares the remote's latest commit with the history you are sending. If the remote has moved on — it contains commits that are not in your copy — your push would silently discard them, so git rejects it as "non-fast-forward": your history does not simply continue from the remote's current tip.
In the AI-builder era this has become an everyday event, because many people now have two writers on one project without realising it. The builder in your browser (Lovable, Bolt, and friends) commits and pushes to GitHub as it works. Meanwhile you clone the repo, make changes locally with a desktop AI tool, and push — straight into the commits the builder made an hour ago. Add the smaller classics: editing a README in the GitHub web interface, fixing a line from a second laptop, a teammate pushing first. All of them produce this exact rejection, and all of them are resolved the same way: combine the histories first, then push.
- A builder pushed: your browser-based AI tool commits to the same GitHub repo as it builds.
- A web edit happened: even a one-line change on github.com is a commit your local copy lacks.
- A second machine or teammate: any push that landed after your last pull puts the remote ahead of you.
- Nothing is lost: a rejected push changes neither copy — it is a checkpoint, not a crash.
Quick answers
Did I lose my work when the push was rejected?
No. A rejected push changes nothing: your commits are sitting safely in your local repository, and the remote is untouched too. The push simply did not happen. Pull to combine the two histories, push again, and everything you made goes up — rejection is a pause, not a loss.
What is the difference between git pull and git pull --rebase?
Both fetch the remote's commits and integrate them with yours. A plain pull usually merges, creating a merge commit where the two histories join. Pull --rebase instead replays your commits one by one on top of the remote's, giving a single straight line. Either unblocks your push; rebase keeps history tidier, merge preserves it exactly as it happened.
When is force pushing actually OK?
Only when the branch is yours alone and you genuinely intend to replace its history — for example, after tidying your own unpublished commits. Even then, --force-with-lease is the safer form because it refuses if the remote changed since you last looked. If a builder or another person also writes to the repo, force pushing can permanently erase their commits; treat it as the last resort, never the first response.