Git reflog, reset and revert: recovering work and shared history
Choose between reflog recovery, reset and revert based on shared history and working-tree state. Rehearse a lost-commit recovery in a disposable repository.
TL;DR: Use reflog to locate a previous local reference value, reset to reposition local history when appropriate, and revert to record an inverse change on shared history. Preserve uncommitted work before any destructive operation, and inspect the exact commit you intend to recover.
Three tools answer different questions
The reflog records local reference movements. It can help find a commit displaced by a reset or rebase, but it is not a remote backup and entries can expire. Create a branch at a recovered commit to make the desired history explicitly reachable.
Reset can move the current branch and, depending on mode, change the index and working tree. Revert creates a new commit that reverses a selected commit's changes, subject to conflicts with later work. Its history remains visible to collaborators.
The official references for reflog, reset and revert define these separate contracts. Learn them as state transitions rather than interchangeable “undo” commands.
| Operation | Branch/history effect | Index and working-tree consequence |
|---|---|---|
reset --soft | Move branch to target commit | Keep index and working tree |
| Default mixed reset | Move branch to target commit | Reset index, keep working tree |
reset --hard | Move branch to target commit | Replace tracked index/worktree state; can remove obstructing untracked paths |
revert | Add inverse-change commit | Apply inverse changes, with possible conflicts |
| Branch from reflog commit | Preserve a recovered history position | Does not inherently switch or discard current work |
Decide whether collaborators depend on the history
Shared history includes more than a branch visible on a hosting service. A colleague may have based work on a commit you sent directly. Ask who depends on the commit graph before rewriting it.
Rehearse a displaced commit safely
Run this example only in a new disposable directory. It creates its own repository, commits two versions and intentionally resets the second committed version. It has no remote and uses a local demonstration identity.
git init -q -b main recovery-demo
cd recovery-demo
git config user.name 'Example Learner'
git config user.email '[email protected]'
printf 'healthy\n' > service.txt
git add service.txt
git commit -qm 'Record initial state'
printf 'candidate\n' > service.txt
git commit -qam 'Record candidate change'
git reset --hard HEAD~1
git reflog --oneline
git branch recovered 'HEAD@{1}'
git show recovered:service.txt
The final command prints candidate. The reset moved main; the reflog retained the previous HEAD value, and the new branch now points at that commit. In a real recovery, inspect the reflog entries and commit contents rather than assuming HEAD@{1} is the desired point. Additional commands can change which entry that expression selects.
This example only recovers committed content. Git cannot promise to restore an arbitrary file edit that was never recorded and was overwritten by a hard reset. Stop and preserve the working tree before experimenting in a repository containing valuable uncommitted work.
Shared rollback is a different operation
Suppose a configuration change has already merged into a shared release branch. A revert produces an auditable corrective commit while keeping the original history intact. Inspect the resulting diff because later changes may depend on the reverted code. Reverting a merge also requires an explicit mainline choice and has consequences for future merges; do not guess at the parent number.
A source revert is not automatically a safe production rollback. The application may have changed data, external resources or compatibility assumptions. Read deployment rollback compatibility before presenting a Git operation as complete recovery.
Similarly, rebase creates new commit identities. If a rebase goes wrong, preserve the previous branch position before trying additional transformations. A recovery branch is cheap evidence; a chain of unexplained resets is harder to reconstruct.
Interview follow-ups
Can another clone's reflog show your local reset? No. Reflogs describe reference movements in that repository. Another clone may contain the original commit through its own refs, but that is a separate recovery source.
Does revert delete the bad commit? No. It adds a new change intended to undo its effect. The original commit remains in history and may still contain sensitive content, which would require a separate incident and history-cleanup procedure.
Why inspect the object model? Understanding commits, trees and refs explains why moving a branch can hide a commit from ordinary log output without immediately erasing the object.