Git Course 0%

When someone pushed before you

Intermediate Git CLI GitLab UI GitHub UI ≈ 9 min

What you will learn

  • How to tell the three rejection messages apart
  • The correct fix for each, and why force is not one of them
  • How to avoid the common cases entirely

After this lesson you can

  • I can read any rejected push and know what to do next without guessing

Why this matters

A rejected push looks like a failure and is usually a courtesy: Git noticed that accepting your push would discard someone else's work, and stopped. The message tells you which situation you are in, if you read past the first line. Three situations cover nearly everything.

Flavour 1: non-fast-forward

Terminal
$ git push
To https://gitlab.com/northwind-trails/trailguide.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'https://gitlab.com/northwind-trails/trailguide.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.

What happened: a colleague pushed commits to the same branch after you last fetched. Your branch and the remote have diverged, and accepting your push would drop their commits.

The fix, exactly as the hint says:

Terminal
$ git pull
$ git push
To https://gitlab.com/you/trailguide.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'https://gitlab.com/you/trailguide.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.

If the pull produces a conflict, resolve it (Section 11) and push afterwards. If your team prefers a linear history, git pull --rebase then push.

Flavour 2: fetch first

What happened: almost the same, but Git has not even fetched the remote's commits yet. The most common cause is a brand-new project created with a README while your folder already had its own history (lesson 7.3).

The fix depends on the cause:

  • A colleague pushed: git pull, then git push.
  • Two unrelated histories (the README case): a plain git pull answers fatal: refusing to merge unrelated histories. Either recreate the project empty, or run it once with permission:

    Terminal
    $ git pull origin main --allow-unrelated-histories
    remote: GitLab: You are not allowed to push code to protected branches on this project.
    To https://gitlab.com/northwind-trails/trailguide.git
     ! [remote rejected] main -> main (pre-receive hook declined)
    error: failed to push some refs to 'https://gitlab.com/northwind-trails/trailguide.git'

    An editor opens for the merge message; save and close, resolve any README conflict, then push.

Flavour 3: protected branch

What happened: the branch accepts changes only through a merge request. Nothing is wrong with your account or your token. Note the two tells: a remote: line, which is the server speaking, and [remote rejected] rather than [rejected].

The fix is to move your commits onto a branch and open a merge request (lesson 6.9):

Terminal
$ git switch -c docs/45-move-my-commits
$ git push -u origin docs/45-move-my-commits

Telling them apart

The message contains Flavour Fix
(non-fast-forward) someone pushed to your branch git pull, then push
(fetch first) the remote has work you have not fetched, possibly unrelated git pull, or --allow-unrelated-histories once
remote: and [remote rejected] the server's own rule, usually branch protection branch and open a merge request
Authentication failed, Access denied not a rejection at all: credentials lesson 7.2

What not to do

How to do it

The whole lesson is two commands, plus reading which flavour you have:

Terminal
$ git pull
$ git push

If the pull conflicts, resolve and push. If the message contains remote:, no amount of pulling helps; branch instead.

Common mistakes

  • Reading only the first line. ! [rejected] is the same for two very different situations; the flavour is in the parentheses and the hints.
  • Reaching for --force. It turns a courtesy into data loss.
  • Pulling repeatedly on a protected branch. No amount of pulling changes the server's rule.
  • Confusing authentication with rejection. Authentication failed happens before any of this and is a token or key problem.

Try it yourself

Goal: produce a real rejected push and fix it properly.

  1. In your playground with a remote, make a commit on the website (edit docs/faq.md in the browser and commit).
  2. Locally, without fetching, make a different commit (edit README.md) and try to push.
  3. Read the message and identify the flavour.
  4. Fix it with git pull, then git push.
  5. Run git log --oneline --graph -4 and see how the two lines joined.

Expected result: step 2 is rejected as non-fast-forward (or fetch first); step 4 succeeds; the graph shows a merge commit joining the web edit and your local commit.

Show solution

The rejection protected the browser commit. The pull merged the two, and because the two commits touched different files there was no conflict to resolve. With a conflict, the same sequence applies with a resolution step in the middle.

Check yourself

1. Your push is rejected with (non-fast-forward). What is the correct next command?
2. Which detail tells you the rejection came from the platform's own rule rather than from Git's fast-forward check?
3. A brand-new project rejects your first push with fetch first, and git pull then says refusing to merge unrelated histories. Why?

Key terms

Push Pull Fetch Protected branch Rewriting history