Fatskills
Practice. Master. Repeat.
Study Guide: TECH **Git Undoing Changes: `git restore`, `git reset`, `git revert`, `git clean`**
Source: https://www.fatskills.com/web-development/chapter/tech-git-undoing-changes-git-restore-git-reset-git-revert-git-clean

TECH **Git Undoing Changes: `git restore`, `git reset`, `git revert`, `git clean`**

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~8 min read

Git Undoing Changes: git restore, git reset, git revert, git clean

A Hyper-Practical, Zero-Fluff Study Guide


1. What This Is & Why It Matters

You’re working on a feature branch, and you accidentally: - Overwrite a critical config file (config.yml) with a bad merge.
- Commit sensitive data (API keys, passwords) and push it to main.
- Delete a directory full of untracked test files you thought were backed up.
- Break the build with a bad commit, and now CI/CD is failing for the whole team.

Git’s undo tools (restore, reset, revert, clean) are your time machine, eraser, and safety net—but they’re also dangerous if misused. In production: - git reset --hard can permanently delete uncommitted work (no recovery).
- git revert is the only safe way to undo commits in shared branches (like main).
- git clean -fd can wipe untracked files (including backups, logs, or local configs).

Real-world scenario:
You’re a DevOps engineer deploying a Kubernetes cluster. A teammate merges a bad Helm chart into main, breaking deployments. You need to: 1. Undo the bad commit without rewriting history (since others have pulled it).
2. Restore a deleted values.yaml file that wasn’t committed.
3. Clean up leftover .tmp files cluttering the repo.

This guide will teach you exactly which tool to use—and when to avoid them.


2. Core Concepts & Components


git restore

  • Definition: Discards changes in the working directory or staging area (replaces git checkout -- <file>).
  • Production insight: Use this to undo local changes before they’re committed. Safer than reset because it doesn’t touch commits.

git reset

  • Definition: Moves the HEAD pointer (and optionally the staging area/index) to a previous commit. Comes in three flavors:
  • --soft: Keeps changes staged.
  • --mixed (default): Keeps changes unstaged.
  • --hard: Destroys uncommitted changes (dangerous!).
  • Production insight: Only use --hard on local branches (never on shared branches like main). --soft is great for rewording commits.

git revert

  • Definition: Creates a new commit that undoes the changes from a previous commit (safe for shared branches).
  • Production insight: The only safe way to undo commits in main/master because it doesn’t rewrite history.

git clean

  • Definition: Removes untracked files/directories from the working directory.
  • Production insight: Use -n (dry run) first! -fd (force + directories) can permanently delete logs, backups, or local configs.

Working Directory vs. Staging Area vs. Repository

  • Working Directory: Your local files (unstaged changes).
  • Staging Area (Index): Files marked for the next commit.
  • Repository: Committed history (.git directory).
  • Production insight: restore and reset operate on different levels—know which one you need!

Detached HEAD State

  • Definition: When HEAD points to a commit instead of a branch (e.g., after git checkout <commit-hash>).
  • Production insight: If you commit here, the changes won’t belong to any branch and may be lost. Always create a branch (git checkout -b new-branch) if you need to save work.

ORIG_HEAD

  • Definition: Git’s "last known good" pointer (updated after dangerous operations like reset --hard or merge).
  • Production insight: If you screw up, git reset ORIG_HEAD can often save you.


3. Step-by-Step Hands-On


Prerequisites

  • A Git repo (local or GitHub).
  • Basic Git knowledge (git add, git commit, git status).
  • ⚠️ Warning: Some commands (reset --hard, clean -fd) are destructive. Use a test repo first!


Task 1: Undo Unstaged Changes (git restore)

Scenario: You modified app.js but haven’t staged/committed it. The changes are bad—discard them.


  1. Check the damage:
    bash
    git status

    Output:
    Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git restore <file>..." to discard changes in working directory)
    modified: app.js

  2. Discard changes in app.js:
    bash
    git restore app.js

  3. Alternative (older Git versions):
    bash
    git checkout -- app.js

  4. Verify:
    bash
    git status

    Output should show no changes.


Task 2: Unstage a File (git restore --staged)

Scenario: You accidentally staged secrets.txt (contains API keys). Unstage it without discarding changes.


  1. Check status:
    bash
    git status

    Output:
    Changes to be committed:
    (use "git restore --staged <file>..." to unstage)
    new file: secrets.txt

  2. Unstage secrets.txt:
    bash
    git restore --staged secrets.txt

  3. Alternative:
    bash
    git reset HEAD secrets.txt

  4. Verify:
    bash
    git status

    Output should show secrets.txt as "untracked."


Task 3: Undo a Commit (git reset)

Scenario: You committed a buggy change to your local branch (feature/login). Undo it.


Option A: Undo Commit, Keep Changes (--soft)

  1. Check commit history:
    bash
    git log --oneline

    Output:
    abc1234 (HEAD -> feature/login) Fix login bug
    def5678 Add login form

  2. Undo the last commit but keep changes staged:
    bash
    git reset --soft HEAD~1

  3. Verify:
    bash
    git status

    Output should show the changes from abc1234 as staged.

Option B: Undo Commit, Unstage Changes (--mixed)

  1. Undo the last commit and unstage changes:
    bash
    git reset HEAD~1

    (Same as git reset --mixed HEAD~1.)

  2. Verify:
    bash
    git status

    Output should show the changes as unstaged.

Option C: Undo Commit, Discard Changes (--hard) ⚠️

  1. ⚠️ Danger! This permanently deletes uncommitted changes.
    bash
    git reset --hard HEAD~1

  2. Verify:
    bash
    git log --oneline

    Output should show def5678 as the latest commit.


Task 4: Undo a Commit in a Shared Branch (git revert)

Scenario: A bad commit (abc1234) was pushed to main. You need to undo it without rewriting history.


  1. Check the commit to revert:
    bash
    git log --oneline

    Output:
    abc1234 (HEAD -> main) Add broken feature
    def5678 Fix login form

  2. Revert the commit:
    bash
    git revert abc1234

  3. Git opens an editor to confirm the revert message. Save and close.

  4. Push the revert commit:
    bash
    git push origin main

  5. Verify:
    bash
    git log --oneline

    Output should show a new commit (e.g., 123defg Revert "Add broken feature").


Task 5: Delete Untracked Files (git clean)

Scenario: Your repo is cluttered with .tmp files and node_modules. Clean them up.


  1. Dry run first! (Shows what will be deleted):
    bash
    git clean -n

    Output:
    Would remove .tmp/
    Would remove node_modules/

  2. Delete untracked files and directories (force):
    bash
    git clean -fd

  3. Verify:
    bash
    git status

    Output should show a clean working directory.


4. ? Production-Ready Best Practices


Security

  • Never git reset --hard on shared branches (e.g., main). Use git revert instead.
  • Use git clean -n first to preview what will be deleted.
  • Avoid committing sensitive data (use .gitignore and git-secrets).

Reliability & Maintainability

  • Use git restore instead of git checkout -- <file> (more intuitive).
  • Tag important commits (e.g., git tag v1.0) before risky operations.
  • Write clear revert messages (e.g., git revert abc1234 -m "Revert broken login API").

Team Workflow

  • Agree on a "no force-push" policy for shared branches.
  • Use git revert for public branches (main, develop).
  • Use git reset only for local branches.

Recovery

  • If you reset --hard by mistake, try: bash git reflog git reset --hard HEAD@{1} # Restore to previous state
  • If you clean -fd by mistake, check backups or git fsck (last resort).


5. ⚠️ Common Mistakes & Traps

Mistake Symptom Fix/Prevention
git reset --hard on main Team members get "diverged history" errors. Use git revert instead.
git clean -fd without -n Deletes important untracked files (e.g., node_modules, .env). Always dry run first (git clean -n).
git revert without -m for merge commits Revert fails with "could not revert" error. Use git revert -m 1 <commit> (specify parent).
git checkout -- <file> instead of git restore Confusing syntax (older Git versions). Use git restore <file> (modern, clearer).
git reset without specifying --soft/--mixed/--hard Defaults to --mixed, which may not be what you want. Always specify the mode.


6. ? Exam/Certification Focus


Typical Question Patterns

  1. "You accidentally staged secrets.txt. How do you unstage it without losing changes?"
  2. git restore --staged secrets.txt
  3. git reset --hard (deletes changes)
  4. git clean -fd (deletes untracked files)

  5. "A bad commit was pushed to main. How do you undo it safely?"

  6. git revert <commit>
  7. git reset --hard HEAD~1 (rewrites history)
  8. git checkout -- <file> (only works for unstaged changes)

  9. "You want to undo the last commit but keep the changes staged. Which command?"

  10. git reset --soft HEAD~1
  11. git reset HEAD~1 (unstages changes)
  12. git revert HEAD (creates a new commit)

Key ⚠️ Trap Distinctions

Command Scope Safe for Shared Branches? Destructive?
git restore Working dir / staging ✅ Yes ❌ No
git reset --soft Commits ❌ No ❌ No
git reset --hard Commits + working dir ❌ No ✅ Yes
git revert Commits ✅ Yes ❌ No
git clean -fd Untracked files ✅ Yes (local only) ✅ Yes


7. ? Hands-On Challenge


Challenge

You’re working on a branch feature/payment. You: 1. Modified payment.js (unstaged).
2. Staged config.yml (but it’s wrong).
3. Committed a buggy change (git commit -m "WIP").
4. Created a .tmp directory with test files.

Your tasks:
1. Discard the unstaged changes in payment.js.
2. Unstage config.yml without losing changes.
3. Undo the last commit but keep the changes unstaged.
4. Delete the .tmp directory.

Solution:


# 1. Discard unstaged changes in payment.js
git restore payment.js

# 2. Unstage config.yml
git restore --staged config.yml

# 3. Undo commit, keep changes unstaged
git reset HEAD~1

# 4. Delete .tmp directory
git clean -fd

Why it works:
- restore targets working dir/staging area.
- reset HEAD~1 (default --mixed) unstages changes.
- clean -fd removes untracked files/dirs.


8. ? Rapid-Reference Crib Sheet

Command Purpose Example
git restore <file> Discard unstaged changes. git restore app.js
git restore --staged <file> Unstage a file. git restore --staged secrets.txt
git reset --soft HEAD~1 Undo commit, keep changes staged. git reset --soft HEAD~1
git reset HEAD~1 Undo commit, unstage changes. git reset HEAD~1
git reset --hard HEAD~1 ⚠️ Undo commit, destroy changes. git reset --hard HEAD~1
git revert <commit> Safely undo a commit (shared branches). git revert abc1234
git clean -n Dry run: show what clean will delete. git clean -n
git clean -fd ⚠️ Delete untracked files/dirs. git clean -fd
git reflog View history of HEAD movements. git reflog
git reset ORIG_HEAD Recover from a bad reset/merge. git reset ORIG_HEAD


9. ? Where to Go Next

  1. Git Official Docs - Undoing Things
  2. GitHub’s "Undoing Changes" Guide
  3. Git Flight Rules (Common Problems & Fixes)
  4. Oh Shit, Git!?! (Funny & Practical Guide)

Final Pro Tip:


"Git’s undo tools are like a chainsaw—powerful, but you’ll lose a limb if you’re not careful. Always git status before and after, and use git reflog as your safety net."


Now go break something (in a test repo) and fix it! ?



ADVERTISEMENT