Emmanuel Corels
← Blog
Cloud & DevOps

Make a local Git branch match origin—with a recovery path

Fetch the exact remote state, classify commits and uncommitted files, create rescue references, reset deliberately and verify the deployed tree.

By Emmanuel Corels

“Force pull” is usually the wrong mental model. git pull fetches and then integrates; it is designed to preserve and combine histories, not declare the remote authoritative. If the operational requirement is “make this local branch and tracked working tree exactly match origin/main,” express those steps directly—and build recovery references first.

Confirm repository, branch and remote identity

git rev-parse --show-toplevel
git status --short --branch
git branch --show-current
git remote -v
git config --get branch.main.remote
git config --get branch.main.merge

Do not assume the branch is main or the authoritative remote is origin. On a deployment host, confirm you are in the intended release checkout and not a shared developer worktree.

Fetch without changing the working tree

git fetch --prune origin
git rev-parse --verify origin/main
git log --left-right --graph --oneline --decorate   main...origin/main

fetch updates remote-tracking references. The left/right log makes local-only and remote-only commits visible before any branch moves.

Inventory everything reset will not summarize for you

git status --short
git diff --stat
git diff --cached --stat
git ls-files --others --exclude-standard
git submodule status --recursive

A hard reset discards tracked working-tree and index changes. It does not remove ordinary untracked files. Submodules and Git LFS introduce additional state that must be verified separately.

Create a durable recovery point

stamp="$(date -u +%Y%m%dT%H%M%SZ)"
git branch "rescue/main-$stamp" main
git stash push --include-untracked   -m "before aligning main to origin/main $stamp"

The rescue branch preserves local commits. The stash preserves tracked modifications, staged changes and untracked files. Ignored files are still excluded; use --all only after reviewing whether ignored build output or secrets would make the stash huge or unsafe.

Move the branch to the fetched remote tip

git switch main
git reset --hard origin/main

This moves main, resets the index, and restores tracked files to the remote-tracking commit. It does not contact the server, which is why the preceding fetch and verification matter.

Handle untracked files separately—and preview first

git clean -nd
git clean -ndX

The first previews untracked, non-ignored paths that git clean -fd would remove. The second previews ignored paths targeted by -X. Never turn a preview into deletion by reflex, especially on deployment hosts where runtime uploads, environment files or generated secrets may sit inside the repository.

If the deployment contract requires a pristine checkout, exclude persistent data from the release directory architecturally. Then, after approving the preview:

git clean -fd

Synchronize submodules and LFS only when the repository uses them

git submodule sync --recursive
git submodule update --init --recursive
git lfs pull

These commands can fetch additional content and change nested working trees. Run them as explicit deployment steps, not as unexplained additions to a generic repair command.

Verify repository state and the running artifact

test "$(git rev-parse main)" = "$(git rev-parse origin/main)"
git status --short --branch
git log -1 --format='%H %cI %s'
git diff --exit-code origin/main --
git diff --cached --exit-code origin/main --

A clean repository does not prove the service deployed successfully. Build or install dependencies through the project’s locked workflow, reload through the service manager, and test the external health and functional routes. Record the deployed commit hash.

Recover local work if the reset was a mistake

git switch -c recovered-work "rescue/main-$stamp"
git stash list
git stash show --stat stash@{0}
git stash apply stash@{0}

Use a separate recovery branch rather than moving main back immediately. Inspect and selectively restore the needed work, then delete the rescue branch and stash only after the recovery window closes.

Choose a less destructive operation when local commits matter

Desired outcomeOperation
Integrate remote changes with local commitsgit pull --rebase or fetch then reviewed rebase
Keep local changes temporarilyStash, update, then apply
Make tracked state equal remoteFetch, rescue, reset --hard
Remove untracked build debrisReview git clean -nd, then targeted clean

Destructive synchronization is safe only when “remote is authoritative” is an explicit decision and every other class of local state has a named recovery path.

Sources: the solved Stack Overflow discussion (CC BY-SA), Git’s official fetch, reset, clean, and user manual.

Primary source: Review the official reference ↗