Push Rejected & Diverged Branches

The symptom

You run git push, confident, and Git slams the door:

What you see

Terminal
$ ! [rejected]        main -> main (fetch first)
$ error: failed to push some refs to 'https://github.com/you/project.git'
$ hint: Updates were rejected because the remote contains work that you do
$ hint: not have locally.
In VS Code
  1. An error toast appears when you push or Sync Changes
  2. The status bar shows a download-arrow count (e.g. ↓1) — commits waiting on GitHub

This is Git's message, not commands to run.

What it means: ahead, behind, diverged

Someone (a teammate — or you, from another computer or a GitHub edit) pushed commits you haven't downloaded yet. Git refuses to overwrite them. git status tells you exactly which situation you're in:

  • "Your branch is ahead of 'origin/main' by 1 commit" — you have work GitHub doesn't. Just push.
  • "Your branch is behind … and can be fast-forwarded" — GitHub has work you don't. Just pull.
  • "Your branch and 'origin/main' have diverged, and have 1 and 2 different commits each" — both happened. Pull first (Git joins the two lines), then push.

VS Code shows the same story as the little arrows in the status bar: ↓2 means two commits to pull, ↑1 means one commit to push. Both at once = diverged.

main feature
Diverged: you and origin/main each added commits since the last sync — pull joins them, then the push works.

The fix: pull, then push

Catch up, then send

Terminal
$ git pull
$ git push
In VS Code
  1. Click Sync Changes (the circular-arrows button in the status bar) — it pulls then pushes in one click

If you and the remote edited the same lines, the pull raises a merge conflict — calmly handled in Fix Merge Conflicts.

That's it, most days. The pull may create a small "merge commit" joining the two lines of work — harmless, and your push goes through right after. If the pull complains about a conflict, Fix Merge Conflicts walks you through it.

A straighter line: pull --rebase

git pull --rebase does the same catch-up but replays your commits on top of the downloaded ones instead of creating a merge commit — the history stays a straight line. It's a nice habit on a branch only you work on.

Rebase-style catch-up

Terminal
$ git pull --rebase
$ git push
In VS Code
  1. Settings → search git rebase when sync → tick Git: Rebase When Sync to make Sync Changes use rebase
  2. Then Sync Changes as usual

The one thing NOT to do

Some tutorials suggest git push --force to "make it work". Don't — force-pushing overwrites the commits on GitHub, including work someone else may have just pushed. On a shared branch that deletes a teammate's work. If a push is rejected, the answer is almost always to pull first, never to force.

Mental model: GitHub's copy and your copy are two notebooks. Push is only allowed when your notebook contains everything theirs does — pull copies their new pages into yours first.

Up next: when the push fails for a different reason — GitHub rejecting your login instead of your commits.

FAQ

Frequently Asked Questions

Why was my git push rejected?
GitHub has commits you don't have locally — a teammate pushed, or you edited on another machine or on github.com. Run git pull to merge them in, then git push goes through.
What does "your branches have diverged" mean?
Both sides moved: you committed locally and new commits landed on GitHub since your last sync. git pull joins the two lines (a small merge commit is normal), then you push.
What do the ↑ and ↓ numbers in VS Code's status bar mean?
counts commits waiting to push; counts commits waiting to pull. Both at once means the branches have diverged — clicking Sync Changes resolves it (pull, then push).
Should I ever use git push --force?
Not on a shared branch — it overwrites commits on GitHub, including teammates' work. If a push is rejected, pull first. Force-pushing is for rewritten history on a branch only you use, and even then --force-with-lease is the safer spelling.