Stage 2 · Tools
Git Fundamentals
Undoing Changes
restore, reset, revert, clean — choosing the right undo for every situation.
git restore — Discard Working Tree Changes
git restore discards changes in your working tree by replacing files with their staged or committed version. This is a destructive operation — the changes are gone. There is no undo.
# Discard changes to a specific file
git restore app.js
# Discard changes to all tracked files
git restore .
# Restore a file from a specific commit
git restore --source=HEAD~2 config.yamlWithout --source, git restore uses the index (staging area) as the source. If you staged changes and want to revert to the last commit, use git restore --staged --worktree app.js to unstage and discard in one step.
git restore cannot be undone. If you discard a change you later need, you can only recover it through the reflog (for committed changes) or not at all (for unstaged, uncommitted changes). Use git stash instead if you might need the changes later.
git restore --staged — Unstage Changes
git restore --staged removes files from the staging area without touching the working tree. The changes remain in your files but are no longer staged for the next commit.
git add app.js
git restore --staged app.js
# app.js is back in working-tree-only state
# The changes still exist in your fileThis is the safe way to undo git add. The file content is untouched — you are only telling Git that this change should not be in the next commit. You can re-stage it later with git add.
git reset — Move Branch Pointers
git reset moves the current branch pointer to a different commit. The --soft, --mixed, and --hard flags control what happens to the staging area and working tree during the move.
git reset --soft HEAD~1
# The last commit is undone
# Changes remain staged in the index
# Working tree is untouchedUse --soft when you want to redo the last commit — maybe the message was wrong or you want to combine it with other staged changes. Everything stays staged, ready for a new commit.
git reset HEAD~1
# Or equivalently:
git reset --mixed HEAD~1
# The last commit is undone
# Changes are unstaged (back in working tree)
# Working tree files are untouched--mixed is the default. It undoes the commit and unstages the changes, but keeps them in your working tree. This is useful when you committed too early and want to reorganize your staging.
git reset --hard HEAD~1
# The last commit is undone
# Staging area is reset to match HEAD~1
# Working tree files are reset to match HEAD~1
# ALL CHANGES ARE LOSTThis is the only reset mode that modifies the working tree. Use it when you are sure you want to throw away the last commit and all its changes. For safety, always commit or stash before a hard reset.
If you git reset a commit that has been pushed to a shared branch, you rewrite history that others may have based work on. Use git revert instead for commits that have been pushed. Reset is safe for local-only work.
git revert — Create a New Commit
git revert creates a new commit that undoes the changes from a previous commit. The original commit remains in history. This is a safe way to undo changes on shared branches because it does not rewrite history.
git revert HEAD
# Opens editor with default message: "Revert 'original commit message'"
# Saves and creates a new commit that undoes the changesThe new commit has the inverse of the original commit's changes. If the original added a line, the revert removes it. If the original deleted a file, the revert restores it.
git revert --no-edit HEAD
# Or revert a range of commits
git revert --no-edit abc1234..def5678--no-edit uses the default commit message without opening an editor. Reverting a range undoes all commits in that range, from oldest to newest.
git clean — Remove Untracked Files
git clean deletes untracked files and directories from your working tree. These are files that Git does not know about and that git checkout cannot touch.
# Dry run — see what would be deleted
git clean --dry-run
# Remove untracked files
git clean -f
# Remove untracked files and directories
git clean -fd
# Remove ignored files too (build artifacts, etc.)
git clean -fdxAlways use --dry-run first to preview what will be deleted. -f forces the operation (Git requires force to prevent accidents). -d includes directories. -x includes files matched by .gitignore.
Choosing the Right Undo
| Command | Affects | Rewrites History? | Safe for Pushed? |
|---|---|---|---|
git restore | Working tree only | No | Yes — local only |
git restore --staged | Staging area only | No | Yes — local only |
git reset --soft | Branch pointer + index | Yes | No — rewrites local history |
git reset --mixed | Branch pointer + index + working tree (partial) | Yes | No |
git reset --hard | Everything | Yes | No — destructive |
git revert | Creates new commit | No (adds commit) | Yes — safe |
git clean | Untracked files only | No | Yes — local only |
If the change has been pushed and shared with others, use git revert. If the change is local and you want to redo it, use git reset. If you just want to discard a mistake in your working tree, use git restore. When in doubt, git stash everything and sort it out later.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.