Undoing changes in Git: restore, reset, revert, and reflog
Pick the undo command by where the mistake lives: in a file, in the staging area, in a local commit, or in a commit you already pushed. The reflog is the safety net for the rest.
Not checked by a trusted editor yet Last edited Outdated?
Git has several undo commands because “undo” means different things. Start by asking where the unwanted change is right now.
Quick guide
- Edited a file and want the last committed version back:
git restore file - Staged something by mistake:
git restore --staged file - Last commit has a typo or a missing file, not pushed yet:
git commit --amend - Want to redo the last local commits:
git reset(see the three modes below) - Commit is already pushed and shared:
git revert - Something is “gone” after a reset, rebase, or deleted branch:
git reflog
restore: files and the staging area
git restore app.py # throw away unstaged edits
git restore --staged app.py # unstage, keep the edits
git restore --source=HEAD~2 app.py # take the file as it was two commits ago
git restore (Git 2.23 and later) replaces the file-related jobs of the older git checkout -- file. Discarded edits that were never committed or stashed cannot be brought back by Git, so check git diff first.
reset: move the branch back
git reset moves the current branch to an earlier commit. The mode decides what happens to the changes from the commits you step over:
Check before you run this
- Can permanently discard commits. Make sure you have a backup branch.
git reset --soft HEAD~1 # undo the commit, keep changes staged
git reset HEAD~1 # --mixed (default): keep changes, unstaged
git reset --hard HEAD~1 # undo the commit AND discard the changes
- –soft is ideal for “I committed too early”: fix things up and commit again.
- –mixed lets you re-stage the changes in smaller pieces.
- –hard also wipes uncommitted work in your working tree. Run
git statusfirst, and stash anything you want to keep.
Only reset commits that you have not pushed, or that live on a branch only you use. Resetting shared history causes the same problems as rebasing it.
revert: undo a pushed commit safely
git revert a1b2c3d
git revert --no-edit HEAD
git revert creates a new commit that applies the opposite of the old one. History is not rewritten, so it is safe on main and on anything others have pulled. Reverting a merge commit needs -m 1 to say which parent to keep.
reflog: the safety net
Every time HEAD moves (commit, reset, rebase, switch), Git writes an entry to the reflog. Commits you “lost” are usually still there:
Check before you run this
- Can permanently discard commits. Make sure you have a backup branch.
git reflog
# cc7a69d HEAD@{0}: reset: moving to HEAD~1
# e50de17 HEAD@{1}: commit: Add price filter
git reset --hard HEAD@{1} # go back to before the reset
git branch rescued e50de17 # or keep it on a new branch
The same trick restores a branch you deleted with git branch -D: find its last commit in the reflog and create a branch there.
The reflog is local to your clone and is not pushed. Old entries are pruned over time (by default after 90 days, or 30 days for commits no branch points to), so recover things soon.
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- Commitpedia +2,816 chars