Shattered Vales Studio Inc.

Undoing Things Safely

Everyone commits to the wrong branch, stages the wrong file, or loses work in a rebase. Git can almost always recover, as long as you don't make it worse in a panic. This guide shows how to pick the right undo command for your situation, and how to rescue work that seems to be gone.

Step 1: Stop and Ask Two Questions

Before typing any undo command, run git status and answer:

  1. Is the work committed? Committed work is almost impossible to lose. Uncommitted work can be deleted permanently by a few commands, so be most careful there.
  2. Has it been pushed to a shared branch? Local, unpushed commits can be rewritten freely. Once others may have pulled them, you must add a commit that undoes them, never rewrite history.

If you're unsure, make a safety bookmark first. It costs nothing and gives you a guaranteed way back:

git branch backup/before-undo

Step 2: Find Your Situation

Is the change committed?
├── No
│   ├── Discard my edits to a file ............... git restore <file>              (Step 3)
│   ├── Unstage a file, keep the edits ........... git restore --staged <file>     (Step 3)
│   └── Set everything aside for later ........... git stash                       (Step 3)
└── Yes
    ├── Not pushed yet
    │   ├── Fix the last commit's message/files .. git commit --amend              (Step 4)
    │   ├── Uncommit, keep the changes ........... git reset --soft HEAD~1         (Step 4)
    │   └── Committed on the wrong branch ........ (Step 6)
    ├── Pushed to a shared branch
    │   └── Undo it for everyone ................. git revert <hash>               (Step 5)
    └── "My commits disappeared" ................. git reflog                      (Step 7)

Step 3: Undo Uncommitted Changes

git restore path/to/file.cs                  # discard edits; the file returns to its last committed state
git restore --staged path/to/file.cs         # unstage; your edits stay in the file
git restore --source=Dev path/to/file.cs     # replace the file with Dev's version

git restore <file> permanently deletes uncommitted edits in that file; there is no undo for it. If there's any chance you want them, stash instead. A stash is a shelf where you can put changes aside, switch branches, and bring them back later:

git stash push -m "half-done tooltip work"    # shelve all tracked changes
git stash push -u -m "including new files"     # -u also shelves untracked files
git stash list                                 # stash@{0}, stash@{1}, ...
git stash pop                                  # re-apply the latest stash and remove it
git stash apply stash@{1}                      # re-apply a specific stash and keep it
git stash drop stash@{1}                       # delete a stash

New files Git has never tracked are removed with git clean. Always preview first with -n (dry run), because deleted untracked files are gone for good:

git clean -n                 # list what would be deleted
git clean -f                 # delete untracked files (add -d to include folders)

Step 4: Undo Commits You Haven't Pushed

Amend replaces the last commit. Use it to fix a typo in the message or add a forgotten file:

git add forgotten-file.cs
git commit --amend               # opens the editor to adjust the message too
git commit --amend --no-edit     # keep the message as it is

Reset moves your branch label back to an earlier commit. HEAD~1 means "one commit before the current one"; HEAD~3 means three. The mode decides what happens to the changes in the commits you remove:

CommandThe removed commits' changes end up…Risk
git reset --soft HEAD~1Staged, ready to commit again.Safe
git reset HEAD~1 (mixed, the default)In your files, unstaged.Safe
git reset --hard HEAD~1Deleted, along with all uncommitted changes in your working tree.Dangerous

The commits removed by any reset can still be recovered with the reflog (Step 7). Uncommitted changes wiped by --hard cannot.

Step 5: Undo Commits That Are Already Shared

Once a commit is on a shared branch, don't reset it away; teammates already have it, and protected branches block force-pushes anyway. Instead, revert it: Git creates a new commit that does the exact opposite. History stays intact, and the undo goes through a pull request like any other change.

git switch -c fix/issue-61-revert-broken-sorting Dev
git revert 3f2a9c1           # new commit undoing 3f2a9c1
git push -u origin fix/issue-61-revert-broken-sorting

To revert a merge commit, tell Git which side to keep with -m 1 (the branch that was merged into): git revert -m 1 <merge-hash>. Reverting a merge has knock-on effects if the same branch is merged again later, so ask a lead before doing it.

Step 6: Move Commits to the Right Branch

Committed on local Dev instead of a feature branch (not pushed)

Create the feature branch where you are (it keeps your commits), then move your local Dev back to match GitHub:

git switch -c feature/issue-42-inventory-sort    # new branch keeps your commits
git switch Dev
git fetch origin
git reset --hard origin/Dev                      # local Dev matches GitHub again
git switch feature/issue-42-inventory-sort

Commit or stash any uncommitted work before running reset --hard.

Need one commit from another branch

Cherry-pick copies a single commit onto your current branch:

git cherry-pick 3f2a9c1

Step 7: Rescue "Lost" Work with the Reflog

The reflog is Git's private diary of every commit your HEAD has pointed at recently, including commits no branch points at anymore after a reset, a bad rebase, or a deleted branch. Entries are kept for about 90 days by default.

git reflog
# 9c4e2b7 HEAD@{0}: reset: moving to HEAD~3
# a81f03d HEAD@{1}: commit: feat(inventory): sort by rarity
# ...

git branch rescue/inventory a81f03d      # put a branch on the lost commit
git log --oneline rescue/inventory       # check it's the work you wanted

The reflog is local to your machine. It can't recover commits that only ever existed on someone else's computer, or changes that were never committed. That's the best argument for committing early and often on your feature branch.

Step 8: Know the Commands That Can Destroy Work

These commands are useful, but they can delete work permanently. Pause before running any of them, and never copy one from the internet without understanding it.

CommandWhat can be lostSafer alternative
git reset --hardAll uncommitted changes.git stash first
git restore .All unstaged edits in every file.Restore specific files
git clean -fdAll untracked files and folders.git clean -n to preview
git push --forceTeammates' commits on the remote branch.git push --force-with-lease
git branch -DUnmerged commits on that branch (recoverable via reflog for a while).git branch -d, which refuses if unmerged
git stash drop / clearShelved changes.git stash pop after checking git stash list