KhueApps
Home/DevOps/Fixing Git push error: remote contains work you do not have

Fixing Git push error: remote contains work you do not have

Last updated: October 07, 2025

What this error means

You tried to push, but the remote branch is ahead of yours. Git prevents you from overwriting remote commits you don’t have locally. The safest fix is to bring those commits into your branch (via rebase or merge), then push.

Error text:

  • fatal: updates were rejected because the remote contains work that you do not have locally

Quickstart: choose the right fix

  • I want to keep my local commits and include remote commits (linear history):
    • git fetch origin
    • git rebase origin/main
    • git push
  • I prefer a merge commit instead of a rebase:
    • git fetch origin
    • git merge origin/main
    • git push
  • I have no local commits to keep (just fast-forward me):
    • git fetch origin
    • git reset --hard origin/main
    • git push (usually not needed)
  • I need my local history to overwrite the remote (be careful):
    • git push --force-with-lease
  • Protected branch (main) disallows force pushes:
    • Create a feature branch, rebase/merge there, then open a pull request.

Replace main with your branch name as needed.

Minimal working example (reproduce and fix)

This simulates a remote, two clones, divergent commits, and a fix via rebase.

# Setup a bare remote
mkdir demo && cd demo
git init --bare origin.git

# Clone A makes the first commit and pushes
git clone origin.git repoA && cd repoA
printf "first\n" > file.txt
git add file.txt
git commit -m "A: first"
git push -u origin main 2>/dev/null || git push -u origin HEAD:main
cd ..

# Clone B diverges
git clone origin.git repoB && cd repoB
printf "B change\n" >> file.txt
git commit -am "B: change"
# This push will fail with the error
set +e
git push
set -e

# Fix: bring in remote commits with rebase, then push
git fetch origin
# Ensure main exists locally
git checkout -B main
git rebase origin/main
# Resolve conflicts if any, then continue
# git add <files>; git rebase --continue

git push

Step-by-step: fetch + rebase (safe, linear)

  1. Ensure your worktree is clean
  • git status
  • If you have local edits, commit or stash them (git stash -u)
  1. Fetch remote changes
  • git fetch origin
  1. Rebase your branch onto the remote tip
  • git rebase origin/main
  • Resolve conflicts as needed:
    • Edit files
    • git add <resolved files>
    • git rebase --continue
    • To abort: git rebase --abort
  1. Push
  • git push
  1. Optional: make rebase your default pull strategy
  • git config --global pull.rebase true

Alternative: merge instead of rebase (non-linear)

  1. Fetch: git fetch origin
  2. Merge: git merge origin/main
  3. Resolve conflicts, commit the merge
  4. Push: git push

Choose merge if your team prefers explicit merge commits or you want to preserve original commit topology.

Overwrite the remote history (use with care)

Only do this when your local history is the correct source of truth and you understand the consequences.

  • Verify what would be replaced:
    • git log --oneline --graph --decorate --boundary origin/main..HEAD
  • Push with safety:
    • git push --force-with-lease

Why --force-with-lease? It refuses to overwrite if the remote moved unexpectedly since your last fetch, reducing the risk of clobbering others’ work.

Note: Some repositories protect main from force pushes. Use a PR workflow instead.

Common scenarios and commands

ScenarioCommand
No local commits to keepgit fetch origin && git reset --hard origin/main
Shallow clone prevents rebasegit fetch --unshallow or increase depth: git fetch --depth=1000
Detached HEAD while updatinggit switch main && git pull --rebase
Rebase gone wronggit rebase --abort
Need to keep tags in syncgit fetch --tags && git push --tags
Upstream not setgit push -u origin main

Diagnostics before fixing

  • See divergence:
    • git log --oneline --graph --decorate HEAD..origin/main
    • git log --oneline --graph --decorate origin/main..HEAD
  • Confirm remotes/branches:
    • git remote -v
    • git branch -vv
  • Confirm you’re on the right branch:
    • git rev-parse --abbrev-ref HEAD

Pitfalls to avoid

  • Using git push --force instead of --force-with-lease: easier to clobber teammates’ work.
  • Running git pull (merge) in a repo that enforces linear history: prefer git pull --rebase or fetch+rebase.
  • Forgetting to stash uncommitted changes before rebase; conflicts become harder to reason about.
  • Rebasing published commits without coordination; others may need to reconcile their history.
  • Shallow clones failing during rebase; unshallow or extend depth first.
  • Large binary conflicts (non-mergeable); consider Git LFS and coordinate a resolution strategy.
  • Submodules: update them explicitly after merge/rebase (git submodule update --init --recursive).

Performance notes

  • Fetch depth for CI: use git fetch --depth=50 (or git clone --depth=50) to reduce network I/O when full history is unnecessary.
  • Partial clone: git clone --filter=blob:none can speed large repos; fetch blobs on demand.
  • Reuse existing packs: frequent incremental fetches are cheaper than occasional massive ones.
  • Compression trade-off: GIT_TRACE_PACKET=1 and core.compression can be tuned, but defaults are fine for most teams.
  • Avoid repeated clean clones in CI where possible; use a cached workspace with git clean -fdx and git fetch --prune instead.

Tiny FAQ

  • Why does this error happen?

    • Because the remote branch has commits you don’t have; Git blocks non-fast-forward pushes by default.
  • Should I use merge or rebase?

    • Rebase yields a linear history and is CI-friendly; merge preserves topology. Follow your team’s policy.
  • How do I abort a rebase with conflicts?

    • git rebase --abort
  • How do I undo a bad force push?

    • If someone has the previous tip, they can push it back. You can also find it via git reflog and push that commit.
  • What if the branch is protected?

    • Create a feature branch, fix via rebase/merge, and open a pull request.
  • I just want my local to match remote, discarding my changes.

    • git fetch origin && git reset --hard origin/main

Summary

Bring the remote commits into your branch (fetch + rebase or merge), resolve conflicts, then push. Force only when necessary, ideally with --force-with-lease, and respect protected branch policies.

Series: Git

DevOps