Skip to main content

Cloudsoft Zone Build, deploy and scale with practical guides to PHP, Node.js, React, DevOps and AI automation. Explore the guides

Cloudsoft Zone
ResourcesTutorial

Git undo cheat sheet: restore, reset, revert and reflog

How to undo almost anything in Git: discard edits, unstage, amend, reset or revert commits, recover deleted branches with the reflog and force-push safely.

Cloudsoft Zone

Updated 7 min read

Many railway tracks and sets of points converging at Clapham Junction, with track workers in orange high-visibility clothing and the London skyline behind
Photograph: Bill Boaden / CC BY-SA 2.0, via Wikimedia Commons
In this article

Almost every Git mistake can be undone, as long as you pick the right command and know whether the work was ever committed or pushed. The trouble is that Git offers five ways to "go back", and the wrong one can throw away uncommitted work for good.

This Git undo cheat sheet groups commands by situation. It explains git restore vs reset vs revert, how to handle git undo local changes safely, fixing the last commit, recovering lost commits with reflog, parking work with stash and force-pushing with --force-with-lease on shared branches.

This cheat sheet groups the undo commands by situation, from discarding an edit to rescuing a deleted branch, and marks which ones are safe on shared branches. Every command was run in a practice repository with Git 2.54 on 9 October 2026 (Git 2.56.0 is the newest release listed on git-scm.com), and the behaviour notes come from the official Git documentation and the Pro Git book.

Close-up of a railway switch, with the movable rails, a blue drive housing between the sleepers and gravel ballast
The moving parts of a railway switch. Reset moves your branch pointer the way a switch moves a train onto another track.

The short answer: git restore discards or unstages changes to files; git reset moves your branch back and rewrites history, so use it only before pushing; and git revert adds a new commit that undoes an old one, which is safe on shared branches.

Pick the right command in ten seconds

I want to...CommandSafe after pushing?
Throw away edits to a filegit restore <file>Yes (local only), but the edits are gone
Unstage a file but keep the editsgit restore --staged <file>Yes
Fix the last commit's message or add a forgotten filegit commit --amendNo: rewrites history
Undo the last commit, keep the changes stagedgit reset --soft HEAD~1No
Undo the last commit, keep the changes unstagedgit reset HEAD~1No
Undo a pushed commitgit revert <commit>Yes: adds a new commit
Get a file back as it was in an old commitgit restore --source=<commit> <file>Yes
Park unfinished workgit stash push -u -m "note"Yes (local only)
Recover a lost commit or deleted branchgit reflog, then git branch <name> <sha>Yes (local only)
Overwrite a remote branch after rewriting itgit push --force-with-leaseOnly on your own branch

The rule behind the third column comes straight from Pro Git: only amend commits that are still local, because amending previously pushed commits and force-pushing "will cause problems for your collaborators". The same applies to reset on any commit others may have pulled.

Undo changes you have not committed

Discard edits in the working tree

Shell
git restore app.txt          # one file
git restore .                # everything under the current directory

Pro Git is blunt about this one: git restore <file> is "a dangerous command", because any local changes to the file are gone. Committed work can nearly always be recovered; work that was never committed usually cannot. If in doubt, stash instead.

Unstage without losing anything

Shell
git restore --staged app.txt # was: git reset HEAD app.txt

git restore and git switch arrived in Git 2.23 to split the many jobs of git checkout into clearer commands. git status prints these hints for you, so read its output before reaching for a command from memory.

Remove untracked files carefully

Shell
git clean -n     # dry run: lists what would be deleted
git clean -f     # actually delete untracked files
git clean -fd    # ...and untracked directories

Always run -n first. In our practice repository it printed Would remove tmp.log and touched nothing.

Fix the last commit

Shell
git commit --amend -m "Better message"   # change the message
git add forgotten.txt
git commit --amend --no-edit              # add a file, keep the message

Amending replaces the commit with a new one; as Pro Git puts it, it is as if the previous commit never happened. Fine on a local branch, a problem on a shared one.

Undo commits: reset versus revert

git reset moves the branch pointer

ModeCommits after the targetStaging areaWorking tree
--softRemoved from the branchChanges kept, stagedUnchanged
--mixed (default)Removed from the branchChanges kept, unstagedUnchanged
--hardRemoved from the branchResetReset: uncommitted edits are lost

git reset --soft HEAD~1 is the cleanest way to "uncommit" and recommit differently, for example to split a commit in two. Use --hard only after checking git status; the commits it removes can be recovered through the reflog, but uncommitted edits cannot.

git revert adds an opposite commit

Shell
git revert a1b2c3d                 # opens an editor for the message
git revert --no-edit a1b2c3d       # use the default "Revert ..." message
git revert -m 1 <merge-commit>     # revert a merge, keeping parent 1 as mainline

The Git documentation describes revert as recording new commits that reverse the effect of earlier ones, which is why it is the right tool on main or any branch others use. Reverting a merge needs -m to say which parent is the mainline, and the documentation warns that it declares you will never want that merge's changes: merging the same branch again later will not bring them back unless you revert the revert.

A manual railway switch lever with a red and yellow disc beside a track in Grötö, Lysekil, Sweden
A hand-operated switch lever in Lysekil, Sweden. Knowing which lever to pull, and when, is most of undoing things in Git.

Rescue work you thought was lost

The reflog: Git's undo history

The reflog records when the tips of branches and other references were updated in your local repository, including every commit, reset, rebase and branch switch. Entries are kept for 90 days by default (gc.reflogExpire), or 30 days for entries no longer reachable from the branch (gc.reflogExpireUnreachable). It exists only on your machine; a fresh clone has none of it.

Shell
git reflog -5
# 73de51a HEAD@{0}: reset: moving to HEAD~2
# 3d2ff30 HEAD@{1}: commit: third again
# ...

git reset --hard 'HEAD@{1}'   # put the branch back where it was before the reset

This is the exact sequence we ran: after a git reset --hard HEAD~2 removed two commits, git reset --hard 'HEAD@{1}' brought both back. Quote HEAD@{1} so shells such as zsh do not interpret the braces.

Restore a deleted branch

Shell
git branch -D experiment
# Deleted branch experiment (was 20e41f8).

git branch experiment 20e41f8     # recreate it from the printed hash
# or find the hash later with: git reflog | grep experiment

Get one file from the past

Shell
git restore --source=HEAD~2 app.txt     # working tree only
git log --oneline -- app.txt            # find the commit you want first

To find the commit that added or removed a piece of text, git log -S "text" --oneline searches the history of changes rather than commit messages.

Park work and switch context

Shell
git stash push -u -m "wip: pricing page"   # -u includes untracked files
git stash list
git stash pop                              # re-apply and drop the stash
git stash apply stash@{1}                  # re-apply, keep the stash

For longer interruptions, such as an urgent fix while a feature is half done, a worktree is often better than a stash. It checks out a second branch in a separate folder that shares the same repository:

Shell
git worktree add ../myapp-hotfix -b hotfix
# fix, commit and push from ../myapp-hotfix, then:
git worktree remove ../myapp-hotfix

Force-pushing safely

If you rewrote your own feature branch with amend, reset or rebase, the remote will reject a normal push. Use --force-with-lease rather than --force: the git-push documentation explains that it refuses the update unless the remote branch still points where your remote-tracking branch says it does, so you cannot silently overwrite a colleague's new commits.

Shell
git push --force-with-lease --force-if-includes origin feature/login

The documentation adds a caveat: if something runs git fetch in the background, such as an editor, the lease check can pass without you ever having seen the new commits. --force-if-includes closes that gap by also checking that the remote tip appears in your local reflog. You can make it the default with git config --global push.useForceIfIncludes true. Never force-push to main; protect it on GitHub or GitLab so nobody can.

How to choose, in one paragraph

Ask two questions. Was it committed? If not, restore and stash are your tools, and anything you discard is gone. Was it pushed to a shared branch? If yes, use revert; if no, amend and reset are fine. And whenever something seems lost, run git reflog before you panic.

Practise before you need it

Create a throwaway repository, make three commits and try each command in this guide. Five minutes of practice is much cheaper than learning reset modes during an incident. For the commit that broke your build, pair this sheet with git bisect; for the full reference, the free Pro Git book and the Git reference manual are maintained on git-scm.com.

Frequently asked questions

  • What is the difference between git reset and git revert?

    reset moves your branch back and removes commits from it, rewriting history. revert adds a new commit that reverses an earlier one, so it is safe on shared branches.

  • How do I undo the last commit but keep my changes?

    git reset --soft HEAD~1 keeps them staged; git reset HEAD~1 keeps them unstaged. Only do this if the commit has not been pushed to a shared branch.

  • Can I recover a branch I deleted?

    Usually, yes. Use the hash printed by git branch -D, or find it with git reflog, then run git branch <name> <hash>.

  • How long does Git keep reflog entries?

    By default 90 days, or 30 days for entries no longer reachable from the branch tip, controlled by gc.reflogExpire and gc.reflogExpireUnreachable.

  • Can I recover changes discarded with git restore?

    Generally no. Uncommitted edits discarded with git restore or git reset --hard are not in the reflog. Stash or commit work you might want back.

  • Why use --force-with-lease instead of --force?

    It refuses to overwrite the remote branch if someone else has pushed since you last fetched. Add --force-if-includes to protect against background fetches too.

Advertise on CloudSoftZone

Your next customer could start right here.

Introduce your tool, product or business to readers exploring technology.

Advertise with us

Explore placements and request a private quote

Sources

  1. Pro Git: Undoing Things — git-scm.com
  2. git-revert documentation — git-scm.com
  3. git-reflog documentation — git-scm.com
  4. git-push documentation — git-scm.com
  5. git-restore documentation — git-scm.com

Comments

No comments yet. Be the first to join the conversation.

Leave a comment

Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.

Never published. Used only to contact you about this comment.

Loading the security check…

Comments are moderated before publication.