Blog
3 min read

Git Push Rejected: "Updates Were Rejected Because the Remote Contains Work"

git push fails with "rejected — fetch first" or "non-fast-forward" when GitHub has commits you don't. How to pull and combine them safely, when force-pushing is fine and when it destroys work, and the other rejection messages: protected branches, large files, and secrets.

 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:you/app.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally.

or

 ! [rejected]        main -> main (non-fast-forward)
hint: Updates were rejected because the tip of your current branch is behind

Git is protecting you. GitHub has commits that your computer doesn't, and if it accepted your push, those commits would be lost. Someone else pushed, you committed from another machine, an AI agent or GitHub Action pushed, or you edited a file on GitHub's website.

The fix: get their work, then push

git pull
git push

git pull downloads the remote commits and combines them with yours. (git fetch vs pull) Then the push succeeds, because your branch now includes everything on GitHub.

Merge or rebase?

Newer versions of git may ask how to combine them:

hint: You have divergent branches and need to specify how to reconcile them.

Pick one (and set it once):

git pull --rebase      # put your commits on top of theirs: tidy, linear history
git pull --no-rebase   # create a merge commit joining both

git config --global pull.rebase true   # make rebase the default

For your own feature branches, rebase is usually nicer. (Git rebase vs merge)

If you get conflicts

Both sides changed the same lines. Git stops and marks them in the files. Resolve them, then:

git add .
git rebase --continue   # if you were rebasing
# or
git commit              # if you were merging
git push

(Merge conflicts explained)

What about git push --force?

Force-pushing tells GitHub "replace your version with mine," deleting the commits you don't have. It's the answer only when you meant to rewrite history — after rebasing or amending your own branch that nobody else uses.

If you must, use the safer variant:

git push --force-with-lease

It refuses if the remote has changed since you last fetched, so you can't wipe out work you've never seen.

Never force-push main or any shared branch to "fix" a rejection. If you already did and lost commits, see how to undo almost anything in git — they're often recoverable from someone's local copy or the reflog.

Other rejection messages

Protected branch.

remote: error: GH006: Protected branch update failed for refs/heads/main.

The repo requires changes to go through pull requests. Push to a new branch and open a PR. (What is a pull request?)

Secret detected.

remote: error: GH013: Repository rule violations found... Push cannot contain secrets

GitHub's push protection found an API key in your commits. Remove it from the commit (not just the latest file), and rotate the key. (I leaked an API key)

File too large.

remote: error: File video.mp4 is 120.00 MB; this exceeds GitHub's file size limit of 100.00 MB

Remove the file from history, add it to .gitignore, and store it elsewhere (or use Git LFS). (What is .gitignore?)

Permission denied. That's an authentication problem, not a rejection. (Permission denied (publickey))

Avoiding it

  • git pull before you start work each session.
  • Work on branches and merge through pull requests.
  • If AI agents push to the same repo, give each its own branch. (Parallel agents with worktrees)

The summary

  • Rejected = the remote has commits you don't.
  • git pull (rebase or merge), resolve conflicts, then push.
  • Use --force-with-lease only on your own branches, never on main.
  • Protected branch, secret and size errors each have their own fix.

EasySpawn keeps your repo on a persistent server where Claude Code works on branches and pulls before it pushes — and you can check in on it from any device. See how it works or join the waitlist.

Related: Git and GitHub for Beginners · Git Rebase vs Merge · How to Undo Almost Anything in Git · Git Fetch vs Pull

Keep reading