Git restore to remote version

Saturday 23/07/2022

·5 min read
Share:

The blunt answer is git reset --hard origin/your-branch — it points your local branch at the remote's commit and discards everything local. It works, it's fast, and it throws away any uncommitted changes silently. That last part is why a lot of people use it once, lose work, and never trust it again. Below: the safe way to do this, the unsafe-but-faster way, and what to do if you've already destroyed something.

The one-liner (with the safety steps)

# 1. Make sure your remote ref is up to date
git fetch origin

# 2. Check what you're about to throw away
git status
git diff origin/main  # or whatever branch you're resetting

# 3. Reset
git reset --hard origin/main

git fetch origin updates your origin/* refs without touching your working tree. Without it, git reset --hard origin/main resets to whatever your last fetch knew about — which might be hours or days out of date.

The middle step (git status + git diff origin/main) is the difference between "I'm sure" and "I'll regret this." Always look before you reset.

What --hard actually does

git reset has three modes:

| Flag | Moves branch pointer | Resets index | Resets working tree | |---|---|---|---| | --soft | yes | no | no | | --mixed (default) | yes | yes | no | | --hard | yes | yes | yes |

--hard rewrites your working files to match the target commit, throwing away any uncommitted edits. --mixed keeps your edits as unstaged changes. --soft keeps your edits and keeps them staged.

For "match my remote exactly," --hard is right. For "rewind history but keep my work in progress," use --mixed or --soft.

Safer alternative: stash first

If you have changes you might want, stash them before resetting:

git stash push -u -m "before-reset"   # -u includes untracked files
git fetch origin
git reset --hard origin/main
git stash list                         # confirm it's there
# later, if you want them back:
git stash pop

A stash is recoverable for at least 30 days (controlled by gc.reflogExpireUnreachable). A hard reset is recoverable too — via the reflog — but stashing makes the intent explicit and the recovery one command away.

Recovering after a mistake

If you've already reset and lost work, git reflog is your friend:

git reflog
# 4a2b3c1 HEAD@{0}: reset: moving to origin/main
# 8d9e0f7 HEAD@{1}: commit: my last work-in-progress
# ...

Each line is a commit your local repo remembers, even if no branch points at it. To restore:

git reset --hard 8d9e0f7

The reflog only knows about commits — uncommitted changes that were never staged are gone. Stage often (git add), commit work-in-progress aggressively (you can always squash later), and the reflog will save you most of the time.

Other patterns worth knowing

Reset to remote and keep your local changes as a stash

git stash push -u
git fetch origin
git reset --hard origin/main
# your work is in `git stash list`

Discard only specific files (not the whole branch)

git fetch origin
git checkout origin/main -- path/to/file.js

This restores a single file from the remote without touching anything else. Useful when you've gone down a wrong path in one file but want to keep edits in others.

Reset only the index, keep working tree

git fetch origin
git reset origin/main   # --mixed is the default

Moves the branch pointer to origin/main but leaves your edits as unstaged changes. Useful for "rewrite my commit history but keep my work."

Force-pull without losing config

If you really mean "make my local exactly mirror the remote," and you want to throw away untracked files too:

git fetch origin
git reset --hard origin/main
git clean -fd            # -f force, -d include directories

git clean -fd deletes everything not tracked by git. Including build artifacts, env files, IDE config you may not have wanted to lose. Use -n first for a dry run.

What NOT to do

  • Don't git pull --force — there's no such flag. git pull runs fetch + merge (or rebase); to override divergent local work, you have to reset explicitly.
  • Don't git push --force without thinking — if your goal is "match remote," you're going the wrong way. Force-push overwrites the remote with your local; you wanted the opposite.
  • Don't rm -rf and re-clone — you'll lose stashes, branches, hooks, and config. Reset is faster and safer.

FAQ

What's the difference between git reset --hard and git checkout?

git reset --hard moves your branch pointer and rewrites the working tree. git checkout origin/main puts you on a detached HEAD at the remote commit without moving your local branch. Use reset to move the branch; use checkout to inspect a state without committing to it.

How do I undo a git reset --hard?

Run git reflog to find the commit you were on before the reset, then git reset --hard <commit-sha>. The reflog keeps that history for 30+ days by default. Uncommitted changes that were never staged are not recoverable.

Does git pull overwrite local changes?

No — git pull will refuse to merge if you have conflicting uncommitted changes. To overwrite local changes with remote, you have to explicitly git reset --hard origin/branch or stash first.

Why does git reset --hard origin/main not pull the latest commits?

Because origin/main is a local pointer to the remote that's only updated when you run git fetch. Always git fetch origin first to make sure origin/main reflects the current remote state.

Share:
VA

Vadim Alakhverdov

Software developer writing about JavaScript, web development, and developer tools.