What Just Happened
You ran git push and got this:
$ git push origin main
To https://github.com/your-org/your-repo.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/your-org/your-repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
Your local branch is behind the remote. A teammate pushed new commits after your last pull, and Git is refusing to let you overwrite their work by pushing on top of your older history.
Git is protecting the remote from losing those newer commits. Same idea as a file conflict, just at the commit level.
Why This Happens
Here's the sequence that causes it:
- You cloned or pulled the repo at commit
A. - A teammate pushed commit
Bto the remote. - You made your own commit
Clocally โ also based onA. - You try to push
C, but the remote is already atB. Your push would eraseBentirely.
Git calls this a non-fast-forward situation. Your branch can't simply move forward in a straight line โ it would have to skip over someone else's work.
Quick Fix: Pull and Merge
For most day-to-day situations on a shared branch, pull first and let Git merge:
# Step 1: Pull the latest changes from the remote
git pull origin main
# Step 2: If there are merge conflicts, resolve them
# (Edit the conflicting files, then:)
git add .
git commit -m "Merge remote changes"
# Step 3: Push again
git push origin main
Git will prompt you for a merge commit message, or auto-generate one. Once the merge succeeds, your push goes through without issue.
Alternative Fix: Pull with Rebase (Cleaner History)
Prefer a straight commit history without merge commits? Use --rebase:
# Pull and rebase your local commits on top of the remote
git pull --rebase origin main
# If there are rebase conflicts:
# 1. Fix the conflicting files
# 2. Stage them
git add
# 3. Continue the rebase
git rebase --continue
# Push after rebase is done
git push origin main
Rebase replays your commits on top of the remote commits. The result looks like you made your changes after the remote ones โ no fork in the history.
Set Rebase as Default Pull Strategy
To make every git pull rebase instead of merge, run this once:
git config --global pull.rebase true
Working Solo on This Branch?
Sometimes this happens when you pushed from a different machine and your current local copy is just stale. A plain pull fixes it:
git pull origin main
git push origin main
If your local commits are drafts you no longer need โ say, you already pushed the real version from another machine โ you can wipe them and reset to the remote:
# Reset local branch to match remote exactly
git fetch origin
git reset --hard origin/main
Warning: --hard permanently discards all local uncommitted changes and any commits not yet on the remote. Only use this when you're certain that local work is disposable.
Force Push โ When and How (Use With Caution)
Force pushing has legitimate uses: cleaning up a messy commit history before a PR, or pushing after rebasing a feature branch that only you've touched.
# Force push (rewrites remote history)
git push --force origin feature/my-branch
A safer option is --force-with-lease. It refuses to push if someone else has pushed since your last fetch โ a useful safety net:
git push --force-with-lease origin feature/my-branch
Never force push to main, master, or any shared branch unless the whole team knows it's happening. Force pushing rewrites history. Anyone who has already based work on those commits will hit painful divergence problems, and there's no easy undo once it's done.
Verify the Fix Worked
After a successful push, confirm local and remote are in sync:
# Check remote tracking status
git status
# Expected: "Your branch is up to date with 'origin/main'."
# View recent commits including remote
git log --oneline -10
# Compare local vs remote directly
git fetch origin
git log HEAD..origin/main --oneline
# No output = fully synced
Checklist: Which Fix to Use
- Shared branch (main, develop) โ
git pullorgit pull --rebase. Never force push. - Your own feature branch, no teammates โ Force push is acceptable after a rebase.
- Local commits are disposable โ
git fetch+git reset --hard origin/main. - Want a clean linear history โ
git pull --rebase.
Keep This From Happening Again
Pull before you start coding each session. It costs five seconds and avoids this entire situation:
# Start every session with:
git pull origin main
# Or just fetch to see what changed without merging yet:
git fetch origin
git log HEAD..origin/main --oneline # See what's new on remote
On teams using feature branches, conflicts on main are rare. The real danger is two people working on the same feature branch without talking first. Keep branches short-lived, communicate before pushing, and this error becomes a rarity.

