Git

How to Resolve "error: failed to push some refs to" on GitHub

4 min read by DebuggedIt

Quick answer

Your git push gets rejected with "failed to push some refs" instead of updating the remote branch. This is Git protecting the remote from a non-fast-forward...

Your git push gets rejected with "failed to push some refs" instead of updating the remote branch. This is Git protecting the remote from a non-fast-forward update β€” meaning someone (or some other machine of yours) pushed commits that your local branch doesn't have yet.

The Problem

You commit locally and run git push, expecting it to succeed, and instead get:

$ git push origin main
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'https://github.com/youruser/yourrepo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.

Sometimes the message is shorter, especially with non-fast-forward rejections on a feature branch:

! [rejected]        feature/login -> feature/login (non-fast-forward)
error: failed to push some refs to 'git@github.com:youruser/yourrepo.git'

Why It Happens

Git only allows a push to update a branch reference when the push is a "fast-forward" β€” meaning your local branch already contains every commit currently on the remote branch, plus your new ones. When that's not true, Git rejects the push instead of silently discarding someone's commits. Typical causes:

  • A teammate pushed to the same branch after your last git pull or git fetch.
  • You committed on two different machines (e.g., laptop and desktop) without syncing between them.
  • You merged or rebased a pull request on GitHub's web UI, which advanced the remote branch beyond what you have locally.
  • You amended or rebased local commits that were already pushed, rewriting history that diverges from the remote's version.

The Fix

In most cases, the correct fix is to integrate the remote's new commits before pushing again. Pull with rebase to keep history linear:

git pull --rebase origin main

If there are conflicting changes, Git will pause and let you resolve them:

CONFLICT (content): Merge conflict in src/app.js
error: could not apply a1b2c3d... your commit message

Resolve the conflict in the listed files, then continue the rebase:

git add src/app.js
git rebase --continue

Once the rebase finishes cleanly, push again:

git push origin main

If you'd rather merge instead of rebase (preserves a merge commit instead of rewriting your commits on top):

git pull origin main
git push origin main

If β€” and only if β€” you're certain the remote commits should be discarded (for example, you rewrote history intentionally with git rebase or git commit --amend on a branch only you use), force-push with lease, which is safer than a plain force push because it fails if someone else pushed in the meantime:

git push --force-with-lease origin main

Avoid plain git push --force on shared branches β€” it silently overwrites the remote's history and can destroy a teammate's commits with no warning.

Still Not Working?

If git pull --rebase itself fails with a different error, like fatal: Not possible to fast-forward, aborting, your local and remote branches may have genuinely diverging histories from a prior rebase or reset. Check the divergence explicitly:

git fetch origin
git log --oneline --graph --left-right main...origin/main

This shows exactly which commits exist only locally (<) and only on the remote (>), so you can decide whether to rebase, merge, or cherry-pick specific commits instead of blindly forcing a push.

It also helps to understand what "fast-forward" actually means in practice, since the term shows up in almost every variant of this error. A fast-forward push is only possible when the remote branch's current tip is an ancestor of your local branch's tip β€” in other words, your local history is the remote's history plus some additional commits on top, with nothing missing in between. The moment someone else's commit lands on the remote that you don't have locally, that ancestor relationship breaks, and Git has no way to safely append your commits without either merging or rebasing first.

If this keeps happening on a branch you push to frequently, especially in a team setting, it's usually a sign of a workflow gap rather than a one-off mistake. Consider adopting a habit of always fetching immediately before you start new work:

git fetch origin
git status

git status will tell you if your branch is behind, ahead, or diverged from its remote counterpart before you even attempt to push, which catches the problem earlier and avoids the rejected push entirely. On protected branches with required pull-request reviews, this error is expected behavior β€” you shouldn't be able to fast-forward push to main directly at all, and the fix there is to open a pull request instead of trying to force your way around branch protection rules.