Git Push Rejected (Non-Fast-Forward): Fix Without Losing Work (2026)

Published February 26, 2026 · 9 min read

If you see ! [rejected] ... (non-fast-forward) or failed to push some refs, Git is protecting remote history. The fix is usually straightforward: sync remote changes, integrate them cleanly, then push again.

Start with a visual diff check: Use Git Diff Viewer before resolving push rejection so you can confirm exactly what will be published after rebase or merge.

Need deeper context on integration strategy? Pair this guide with Git Rebase Complete Guide when choosing between rebase and merge for your branch policy.

Table of contents

  1. Why this error happens
  2. Quick safe fix flow
  3. Rebase vs merge decision
  4. When force-with-lease is valid
  5. Troubleshooting edge cases
  6. FAQ

1. Why this error happens

A fast-forward push means your branch tip simply moves forward from the remote tip. A non-fast-forward rejection means the remote already moved in another direction (for example, teammate commits or CI bot updates), and your push would overwrite history.

Message Meaning Safe default
non-fast-forward Remote branch has commits you do not have locally Fetch, integrate, push again
failed to push some refs Push was rejected for one or more refs Inspect branch + upstream mapping, then sync
updates were rejected Server blocked update due to divergence or policy Use pull --rebase or merge, do not force on shared branch

2. Quick safe fix flow

# 1) Confirm branch and upstream
 git status -sb

# 2) Fetch latest remote state
 git fetch origin

# 3A) Rebase local commits on top of remote
 git rebase origin/your-branch

# or 3B) Merge remote into local branch
 git merge origin/your-branch

# 4) Resolve conflicts if they appear
 git add .
 git rebase --continue   # if rebasing
 # or: git commit        # if merging

# 5) Push after successful integration
 git push origin your-branch
Team-safe default: On shared branches, integrate remote commits first and push normally. Avoid force push unless your team explicitly allows history rewrite.

3. Rebase vs merge decision

Both approaches fix non-fast-forward rejection. Choose the one that matches repo policy.

Approach Best for Command
Rebase Linear history, clean PR timeline git pull --rebase origin your-branch
Merge Preserving exact branch topology git pull origin your-branch
Do not rebase public shared history without coordination. If others based work on your branch, rebasing can force them into conflict recovery.

4. When force-with-lease is valid

Use --force-with-lease only when you intentionally rewrote your own branch history (for example, interactive rebase or squash) and you understand the branch ownership.

# Safe force pattern after intentional history rewrite
 git push --force-with-lease origin your-branch

Do not replace lease with plain --force. Lease protects against clobbering remote updates you have not seen yet.

5. Troubleshooting edge cases

Upstream branch is not set

git push -u origin your-branch

Rebase conflict loop

git status
# resolve files
 git add <files>
 git rebase --continue
# or abort if needed
 git rebase --abort

You accidentally force-pushed wrong history

git reflog
 git checkout -b recovery/non-fast-forward <good-hash>
 git push origin recovery/non-fast-forward

If you only need to undo the last local commit before retrying push, follow Undo Last Commit in Git and then repeat the safe sync flow.

6. Frequently asked questions

Can I run git push --force to bypass non-fast-forward quickly?

Only if branch policy allows rewrite and you are certain nobody else depends on that history. Prefer --force-with-lease, not --force.

Is git pull --rebase always the right fix?

It is often preferred for cleaner history, but some teams require merge commits. Follow repo conventions.

Why does this happen even when I just pulled?

Remote can change again between your pull and push window. Fetch again, re-integrate if needed, and retry.

Continue with related guides: Git Rebase Complete Guide · Git Force Push Safety Checklist · Undo Last Commit in Git