Master how to undo changes in Git: git restore for files and the staging area, git revert to safely undo commits, and git reset to move HEAD with the three modes soft, mixed, and hard along with their risks.

In episode 13 we secured the repository against incidents. Now for a more common incident: the small everyday mistakes — editing the wrong file, staging the wrong thing, or making the wrong commit. The good news is that Git is a time machine: almost every decision can be undone as long as you know the right tool. The bad news is that the wrong tool can destroy your work.
The key is understanding which area the change lives in. Recall the three areas from episode 2: the working directory (where you edit), the staging area (where things sit before committing), and the repository (commit history). Every undo command works on a specific area — choosing the wrong command is like rewinding time in the wrong era.
Changes that have not been staged — never passed through git add — can be undone with git restore <file>. This command returns the file's contents to the state of the last commit (or HEAD).
git restore src/utils/login.ts
git statusAfter the command above, the file src/utils/login.ts returns to the last committed version and disappears from the modified list.
Warning
git restore <file> overwrites the file without confirmation and the discarded changes cannot be recovered — unlike commits, which can still be recovered through the reflog. Make absolutely sure you no longer need those changes before running it.
If a change has already been git add-ed but not committed, remove it with git restore --staged <file>. The changes stay in the working directory — only the staging entry is removed:
git restore --staged src/utils/login.ts
git statusNotice the result of git status: the file is now in the "Changes not staged" list — the content is intact, only the staging entry is cleared. This is the opposite of git add, and the modern replacement for the once-popular git reset HEAD <file>.
A mistake that is already committed is the next level up. There are two main commands: git revert and git reset. Start with the safest.
git revert <hash> creates a new commit whose content reverses the changes of an old commit. History is not rewritten — only appended. That is why it is safe for public branches shared by the team (remember the golden rule from episode 7: never rewrite public history).
git revert 9f3b2c1
git log --oneline -4Now the log contains a Revert "..." commit as the newest child — all other commits remain intact. Teammates who already pulled this branch will not run into conflicts.
git reset <hash> moves the branch pointer (HEAD) backward to a specific commit, as if the commits after it "never happened". This changes history, so it is only for local branches that have not been pushed. Three modes determine the fate of your changes:
git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1The difference lies in what happens to the staging area and working directory:
| Mode | HEAD | Staging Area | Working Directory |
|---|---|---|---|
--soft | Backward | Changes stay staged | Changes stay intact |
--mixed (default) | Backward | Cleared | Changes stay intact |
--hard | Backward | Cleared | Changes deleted |
Warning
git reset --hard permanently destroys changes — the staging area and working directory are cleared mercilessly. Only use it on local commits you genuinely want to discard, and never on a public branch. To undo public commits, always use git revert.
Because --mixed is the default, a plain git reset <hash> is enough to undo the last commit while keeping its changes in the working directory — then you can pick and choose which parts to commit again.
When several consecutive commits must be undone, combine them with the HEAD~N range:
git reset --soft HEAD~3
git status
git commit -m "feat: gabungkan tiga commit menjadi satu"To revert several commits at once, run git revert one by one from newest to oldest, or use a range: git revert <start-hash>^..<end-hash>. Recall the rule: reset is only for local branches that have not been shared; revert is for history that has already been pushed and is used by the team.
A complete summary of when to use which command:
| Command | Target | Creates a New Commit | Safe for Public Branches | Use Case |
|---|---|---|---|---|
git restore <file> | Working directory | No | Yes | Undo file edits |
git restore --staged <file> | Staging area | No | Yes | Unstage a file |
git revert <hash> | History | Yes | Yes | Undo an old commit |
git reset <hash> | History | No | No | Move HEAD backward |
Tip
Rule of thumb: not yet committed → git restore; already pushed and used by the team → git revert; local commits not yet pushed → git reset. If you are unsure whether others use the branch, assume it is public and choose git revert.
Losing a commit because of git reset is not the end of the world: git reflog records every HEAD movement and can recover "deleted" commits — we will examine it thoroughly in episode 17.
This episode gives you a safe Git time machine: git restore <file> undoes edits in the working directory, git restore --staged <file> removes a file from staging without deleting changes, git revert <hash> undoes a commit by creating a new one that is safe for public branches, and git reset <hash> moves HEAD with the three modes soft, mixed, and hard.
The points to take with you:
git revert is safe for public history; git reset is only for local branches.--soft keeps the staging area, --mixed (default) keeps the working directory, --hard removes everything.git reset --hard destroys changes — use it with full awareness.You have mastered the time machine, but what about work that is half-finished when you suddenly have to switch branches? In episode 15 we cover Git Stash & Git Clean — stashing temporary changes in a closet and safely cleaning up untracked files. See you in episode 15!