Git Push Rejected: "fetch first" — What To Actually Do
⏱️ 2 min read
! [rejected] (fetch first) means the remote branch has commits your local branch doesn't, and Git refuses to overwrite them. The fix is always: bring the remote commits in, then push. The only question is how — and the answer decides whether your history stays readable.
The 30-second fix
git fetch origin, then git rebase origin/main (or your branch), resolve any conflicts, then git push. Rebase replays your commits on top of the remote ones, so the history reads as if you wrote your work after theirs — a clean line, no "Merge branch" knot.
Rebase vs merge, honestly
Rebase keeps history linear and is what most teams expect on feature branches. If conflicts appear, you resolve them commit-by-commit (or git rebase --continue after each). Merge (git pull with merge) creates a merge commit; it's fine for shared long-lived branches where you don't want to rewrite anything. The disaster case is the reflexive git pull origin main -r mixed with --force pushes on shared branches — don't force-push anything anyone else builds on.
After a bad pull
If you already pulled with merge and regret the history, git reflog finds your pre-pull position, and git reset --hard <hash> restores it. Then do the rebase properly. Reflog makes this reversible, not destructive.
Prevention beats resolution
Pull before you start working (not just before you push), push small commits often, and enable pull.rebase=true or pull.ff only to make your default behavior deliberate. Want to practice conflict resolution without risking real repos? A disposable VM with a scratch clone — hourly servers cost cents — is a stress-free git dojo.