Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Git Pull Force Overwrite: There Is No --force, and What to Use Instead

Sean

Platform Writer

Aug 26, 2026
8 min read

git pull --force does not discard your local changes — it only relaxes the check on the fetch side. To make your branch exactly match the remote, fetch first and then hard reset: git fetch origin && git reset --hard origin/main. Untracked files survive that, so git clean -fd is usually the second half of what people actually want.

Git Pull Force Overwrite: There Is No --force, and What to Use Instead

Almost everyone arrives here after a merge conflict they did not want, on changes they do not care about, on a branch they just want to look like the server. The instinct is to add --force to git pull and move on.

It will not do it. Understanding why takes about a minute, and it is the difference between reliably resetting a branch and occasionally destroying work you meant to keep.

Table of contents

Why —force does not do what you expect

git pull is git fetch followed by git merge. The --force flag is passed to the fetch half, where it means: allow updating the local tracking ref even if it is not a fast-forward.

It says nothing about your working directory. Your modified files are still modified, the merge still runs, and the conflict you were trying to avoid still happens.

What people actually want is a different operation: throw away local state and make this branch identical to the remote. That is a reset, and Git keeps it as a separate command deliberately, because it destroys work and should be typed on purpose.

The three-step version, which is the one to memorise:

git fetch origin
git reset --hard origin/main
git clean -fd

Fetch updates your knowledge of the remote. Reset moves your branch and working tree to match it, discarding tracked-file changes. Clean removes untracked files, which reset leaves alone.

What each step actually destroys

Worth being precise, because the three commands have different blast radii.

git fetch origin destroys nothing. It only downloads. You can run it any time, and running it first means the reset targets something real rather than a stale ref.

git reset --hard origin/main discards uncommitted changes to tracked files and moves your branch pointer. Committed work is not gone — it stays in the reflog for around 30 days — but uncommitted edits are genuinely unrecoverable.

git clean -fd deletes untracked files and directories. This is the one that catches people, because it will happily remove a .env file, local uploads, or a config you never committed. Preview it first, always:

git clean -nd    # dry run: lists what WOULD be deleted
git clean -fd    # actually delete

Note that git clean respects .gitignore by default, so ignored files survive unless you add -x. Adding -x to the command is how people delete node_modules, their local database file and their environment config in one go.

Keeping your work instead of destroying it

Before reaching for a hard reset, it is worth knowing the two commands that make it reversible, because they cost nothing.

Stash. Puts your changes aside and gives you a clean tree:

git stash push -u -m "wip before reset"
git pull
git stash pop     # bring them back, or drop them

The -u matters — without it, untracked files are not stashed and will still be there afterwards.

A throwaway branch. Even simpler, and it survives a stash list you forget to read:

git switch -c backup-before-reset
git add -A && git commit -m "snapshot"
git switch main
git reset --hard origin/main

Now the work is a commit on a branch you can return to or delete. This costs about five seconds, and it converts an irreversible operation into a reversible one.

Resetting a branch other than main

The command generalises, and the mistake people make is resetting to the wrong upstream.

git fetch origin
git reset --hard origin/feature-x

If you want to reset to whatever the current branch tracks, without naming it, @{u} refers to the upstream:

git fetch origin
git reset --hard @{u}

That is safer in a script, because it cannot accidentally reset your feature branch to main.

Two related situations worth separating:

  • Someone force-pushed and your branch diverged. Reset is correct — your local history references commits that no longer exist upstream.
  • You have local commits you want to keep on top of the new remote history. Reset is wrong. Use git pull --rebase to replay your commits onto the updated base.

Confusing those two is the main way people lose commits they meant to keep.

Recovering when you reset something you needed

If the work was committed, it is almost certainly still there. The reflog records every position your HEAD has been in:

git reflog
# 8a3f2c1 HEAD@{0}: reset: moving to origin/main
# f91b4e7 HEAD@{1}: commit: the work you just lost

Recover it by branching from the old position:

git switch -c recovered f91b4e7

Reflog entries expire after roughly 30 days for reachable commits and 90 for unreachable ones, so this is a real safety net rather than a theoretical one — but it only covers commits.

Uncommitted changes wiped by reset --hard, and untracked files removed by git clean, are gone. No reflog, no recovery. That asymmetry is the entire argument for the throwaway-branch habit above: committing takes five seconds and moves your work into the category Git can get back.

How this fits the rest of the stack

The distinction underneath all of this is between state that is recorded and state that only exists on one machine. Committed work is recoverable, pushed work is durable, and everything else is one mistyped command from gone. That is worth internalising well beyond Git, because deployments have the same property.

A deploy that came from a commit can be rebuilt and rolled back. A deploy that came from files someone copied onto a server cannot. RunxBuild builds from a connected GitHub repository, keeps per-deploy build and runtime logs, and lets you roll back to a previous deploy — so the running version always has a commit behind it. The RunxBuild hosting calculator shows what a service, database and storage come to together if you are sizing that up.

Useful related references:

FAQ

Does git pull —force overwrite local changes?

No. The flag applies to the fetch half of the operation and only relaxes the fast-forward check on updating refs. Your working directory is untouched and the merge still runs. To overwrite local changes you need git fetch followed by git reset --hard origin/main.

What is the difference between git reset —hard and git clean?

reset --hard discards changes to files Git is tracking and moves your branch pointer. git clean deletes untracked files and directories, which reset does not touch. Making a branch exactly match the remote usually needs both.

Can I recover work after git reset —hard?

If it was committed, yes — find the old position in git reflog and branch from it with git switch -c recovered <hash>. If it was uncommitted, or was an untracked file removed by git clean, it is unrecoverable. That asymmetry is why committing to a throwaway branch first is worth the five seconds.

How do I preview what git clean will delete?

Use git clean -nd for a dry run listing every file and directory it would remove. Note that clean respects .gitignore by default, so adding -x also removes ignored files — which is how people accidentally delete .env files and local databases.

Should I use reset —hard or pull —rebase?

Reset when you want to discard local history entirely and match the remote, typically after someone force-pushed. Rebase when you have local commits worth keeping and want them replayed on top of the updated remote history. Choosing reset in the second case is how commits get lost.

#git pull force overwrite#git#git reset#version control#git clean