Undoing Changes

Git · Lesson 8 of 28 8 min read Updated

Everyone makes mistakes: you edit the wrong file, stage something by accident, commit with a typo in the message, or commit a change that breaks the site. Git can undo all of these, but there are several commands and each works on a different area. Choosing the wrong one can throw away work, so this lesson goes slowly.

You will learn git restore for uncommitted changes, git commit --amend for the last commit, git reset for moving a branch back, and git revert for undoing a commit that others already have.

Discarding changes in the working tree

Priya accidentally pastes some random text into index.html. She has not staged it. git restore replaces the file with the version from the index, which throws away the edit:

Terminal
git status -s
git restore index.html
git status -s
Output
M index.html

The second git status -s printed nothing: the file is back to normal. Be careful, because this edit is gone for good. Git never saved it, so even Git cannot bring it back. Use git restore . to discard every unstaged change in the current folder.

Unstaging a file

Next she changes a price in menu.html and stages it, then realises the price is not final. To take it out of the index but keep the edit in her file, she adds --staged:

Terminal
git status -s
git restore --staged menu.html
git status -s
Output
M  menu.html
 M menu.html

The M moved from the left column (index) to the right column (working tree). Nothing is lost. Notice that git status itself always prints the right command as a hint, so read its output when you are unsure.

You can also restore a file from any older commit with --source. This copies the home page as it was in the first commit into your working tree, ready to be reviewed and committed:

Terminal
git restore --source=dae5ca8 index.html

Fixing the last commit with --amend

Priya commits a new style with a typo in the message:

Terminal
git commit -qam "Add pirce style"
git commit --amend -m "Add price style"
Output
[main b689648] Add price style
 Date: Fri Oct 30 14:36:03 2026 +0530
 1 file changed, 3 insertions(+)

--amend replaces the last commit with a new one. Notice the hash changed (it was 00fcd79 before), because a commit's ID depends on its content and message. Amend also helps when you forgot a file: stage it and run git commit --amend --no-edit to add it to the last commit while keeping the message.

Since amend creates a new commit, only amend commits you have not pushed yet. If teammates already have the old commit, rewriting it causes confusion (you will see why in Rebasing).

Moving a branch back with git reset

git reset <commit> moves the current branch to point at an older commit. The commits after it are no longer on the branch. The three modes decide what happens to the changes from those commits:

ModeBranch moves backIndexWorking treeUse it to
--softYesKeeps the changes stagedUnchangedRedo the last commits as one new commit
--mixed (default)YesChanges become unstagedUnchangedUndo commits but keep editing the files
--hardYesReset to the commitReset to the commitThrow the commits and all changes away

Here is --soft undoing the last commit; its changes wait in the index:

Terminal
git reset --soft HEAD~1
git status -s
Output
A  contact.html
M  main.css

A plain git reset (mixed) then unstages them too, leaving them only as edits in the files:

Terminal
git reset
git status -s
Output
Unstaged changes after reset:
M	main.css
 M main.css
?? contact.html

And --hard removes a commit together with its changes. Priya tries an experiment, commits it, and decides to throw it away:

Terminal
git reset --hard HEAD~1
Output
HEAD is now at 17bb4f7 Add price style and contact page

Undoing a shared commit with git revert

reset rewrites history, which is fine for your own unpushed commits but harmful once others have pulled them. For a commit that is already shared, use git revert. It does not delete anything. It creates a new commit that applies the exact opposite of the old one.

Priya changed the opening hours, pushed it, and the shop owner says the change was wrong:

Terminal
git revert --no-edit HEAD
git log --oneline -3
Output
[main 24d8d06] Revert "Change opening hours"
 Date: Fri Oct 30 14:36:58 2026 +0530
 1 file changed, 1 insertion(+), 1 deletion(-)
24d8d06 (HEAD -> main) Revert "Change opening hours"
84059e3 Change opening hours
17bb4f7 Add price style and contact page

Both the mistake and its reversal stay in the history, which is honest and safe: everyone simply pulls one more commit. Without --no-edit, Git opens your editor so you can explain why you reverted, which is a good habit. You can revert any older commit by its hash, not just the latest one.

Which command should I use?

  • Changed a file and want the last saved version back: git restore <file>.
  • Staged something by mistake: git restore --staged <file>.
  • Typo in the last commit message, or forgot a file, and not pushed yet: git commit --amend.
  • Want to undo your last few local commits but keep the work: git reset HEAD~n (mixed) or --soft.
  • Want to throw away local commits and changes completely: git reset --hard <commit>.
  • Need to undo a commit that is already pushed or shared: git revert <commit>.

Common mistakes

  • Using reset --hard when you meant to unstage. Unstaging is git restore --staged; it never touches your edits.
  • Amending or resetting pushed commits. Teammates' history then disagrees with yours. Use git revert for shared history.
  • Expecting Git to recover unsaved edits. Changes you never staged or committed are not in Git at all.

Key points

  • git restore <file> discards working-tree changes; --staged unstages; --source=<commit> restores an older version.
  • git commit --amend replaces the last commit; use it only before pushing.
  • git reset moves the branch back: --soft keeps changes staged, --mixed keeps them unstaged, --hard deletes them.
  • git revert makes a new commit that undoes an old one, and is the safe choice for shared history.
  • Read git status: it prints the right undo command as a hint.

Exercise

In a practice repository: (1) edit a tracked file and discard the edit; (2) stage a change and unstage it without losing it; (3) commit with a misspelt message and fix the message; (4) make a commit, push it in your mind as "shared", and undo it the safe way. Write down the command for each step.

Show solution
Terminal
git restore notes.txt
git restore --staged todo.txt
git commit -m "Ad shopping list"
git commit --amend -m "Add shopping list"
git revert --no-edit HEAD

Step 1 and 2 use git restore, step 3 uses --amend because the commit is still local, and step 4 uses git revert because the commit is shared, so you add a new undo commit instead of rewriting history.

Quick Quiz

1. You staged menu.html by mistake. Which command unstages it and keeps your edits?

2. Which git reset mode keeps the undone commit's changes staged?

3. A bad commit is already on GitHub and your team has pulled it. What should you use?

4. Why does git commit --amend give the commit a new hash?

Learn Git with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call