Fix: git push rejected – non-fast-forward error
The Error
You run git push and get:
To github.com:user/repo.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to 'github.com:user/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.Why This Happens
Git is telling you that the remote branch has commits that your local branch does not. Your local history and the remote history have diverged, so Git refuses to push because doing so would overwrite those remote commits.
Common causes:
- A teammate pushed to the same branch. Someone else merged or pushed new commits to
mainwhile you were working locally. - You pushed from another machine. You committed and pushed from your laptop, then tried to push older local state from your desktop.
- You amended or rebased locally. Running
git commit --amend,git rebase, orgit resetrewrites commit history. The rewritten commits have different hashes than what the remote already has, so Git sees them as divergent. (Rebasing can also leave you in a detached HEAD state if interrupted.) - A PR was squash-merged on GitHub/GitLab. You merged your feature branch through the web UI with “Squash and merge,” then tried to push the original (non-squashed) branch again.
In all of these cases the underlying problem is the same: your local branch tip is not a direct descendant of the remote branch tip, so a push would lose commits.
Fix 1: Pull and Merge (Safest)
The simplest fix. Fetch the remote commits and merge them into your local branch:
git pull origin mainThis creates a merge commit that joins the two histories together. Resolve any merge conflicts if they appear, then push:
git push origin mainThis is the safest option because no commits are lost or rewritten. The downside is that it adds a merge commit to your history.
Fix 2: Pull with Rebase (Cleaner History)
If you prefer a linear history without merge commits, rebase your local commits on top of the remote ones:
git pull --rebase origin mainThis takes your local commits, temporarily removes them, pulls the remote commits, then replays your commits on top. If there are conflicts, Git will pause and ask you to resolve them one commit at a time. After resolving:
git rebase --continueOnce the rebase is complete, push normally:
git push origin mainUse this when you have a small number of local commits and want a clean, linear history.
Fix 3: Force Push with Lease (Safe Override)
If you intentionally rewrote history (for example, after an interactive rebase or amend) and you want the remote to match your local branch, use --force-with-lease:
git push --force-with-lease origin main--force-with-lease checks that the remote branch is still at the commit you last fetched. If someone else pushed new commits since your last fetch, the push is rejected. This prevents you from accidentally overwriting a teammate’s work.
Only use this when you understand that you are replacing the remote history with your local history. This is appropriate after an intentional rebase or amend, not as a workaround for being behind.
Fix 4: Force Push (Use with Extreme Caution)
git push --force origin mainThis unconditionally overwrites the remote branch with your local branch. It does not check whether someone else pushed in the meantime.
Only use --force on personal branches that nobody else is working on. Never force push to a shared branch like main or develop unless you have coordinated with your team and everyone is aware.
—force vs —force-with-lease
--force | --force-with-lease | |
|---|---|---|
| Overwrites remote | Yes, unconditionally | Only if remote hasn’t changed since your last fetch |
| Risk of losing others’ work | High | Low (fails if remote was updated) |
| When to use | Personal/throwaway branches only | After intentional local history rewrites |
In practice, prefer --force-with-lease whenever you need to force push. There is almost no reason to use --force on any branch that others might be using.
Still Not Working?
Protected branches block force push
GitHub, GitLab, and Bitbucket allow administrators to protect branches. If main is protected, you will see an error like:
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: Cannot force-push to this protected branch.In this case you cannot force push at all. You must use Fix 1 or Fix 2 to integrate the remote changes, or ask a repository admin to temporarily disable branch protection.
On GitHub, this is under Settings > Branches > Branch protection rules. On GitLab, it is under Settings > Repository > Protected branches.
Diverged branches after a rebase
If you rebased a feature branch that was already pushed, your local and remote copies of that branch have diverged. A normal push will fail. This is expected. Use --force-with-lease to update the remote:
git push --force-with-lease origin feature-branchThis is a normal part of rebase workflows. Just make sure no one else is basing work on that branch, or coordinate with them first.
First push to a new remote with existing commits
If you initialized a repo locally and are pushing to a new remote that already has commits (for example, GitHub created a repo with a README), the histories are completely unrelated. You will see:
! [rejected] main -> main (fetch first)Fix this by pulling with --allow-unrelated-histories (see our full guide: Fix: fatal: refusing to merge unrelated histories):
git pull origin main --allow-unrelated-historiesResolve any conflicts, then push:
git push origin mainYou fetched but the error persists
If git pull --rebase still fails, your local branch might be tracking the wrong remote branch. Verify with:
git branch -vvMake sure your branch is tracking origin/main (or whichever remote branch you intend). If it is not, set the upstream:
git branch --set-upstream-to=origin/main mainThen pull and push again. If you get a Permission denied (publickey) error when pushing, see Fix: git permission denied (publickey).
Related Articles
Fix: CONFLICT (content): Merge conflict in file — fix conflicts and then commit the result
How to fix Git merge conflicts during merge, rebase, cherry-pick, and pull — resolve conflict markers, use merge tools, accept theirs or ours, abort, and prevent future conflicts.
Fix: fatal: not a git repository (or any of the parent directories): .git
How to fix the 'fatal: not a git repository' error in Git by checking your working directory, initializing a repo, recovering a deleted .git folder, and resolving submodule, CI/CD, and IDE path issues.
Fix: git stash pop – CONFLICT, local changes would be overwritten, no stash entries found
How to fix git stash errors: 'CONFLICT' after git stash pop, 'Your local changes to the following files would be overwritten', 'No stash entries found', and 'Could not restore untracked files from stash entry'. Covers stash pop vs apply, conflict resolution, recovering dropped stashes, and stashing untracked files.
Fix: You are in 'detached HEAD' state
How to fix Git's 'detached HEAD' state, 'HEAD detached at xxx', 'HEAD detached from xxx', and 'Warning: you are leaving X commits behind'. Covers creating a branch, saving commits, recovering lost work with reflog, and when detached HEAD is intentional.