Git Restore vs Reset vs Revert: A Practical Guide to Undoing Changes

Learn when to use git restore, git reset, and git revert with a tested local lab. Understand staged changes, safe local history edits, and how to undo a shared commit.

By Network Nuts Team · Published 2026-10-13

You changed a configuration file, staged it, and then realised it belongs in a different commit. Or a committed change needs to be undone after teammates have pulled it. Both situations sound like “undo,” but they need different decisions.

This guide uses a small configuration-file lab to show what Git changes at each step. The examples run locally, need no remote repository, and do not deploy anything. Use a disposable directory, not a checkout containing work you need to keep.

First identify what you want to change

Keep three locations in mind:

  • Working tree: the files you are editing.
  • Index, or staging area: the content prepared for the next commit.
  • HEAD: the currently checked-out commit; on a normal branch, it follows that branch’s tip.

Start with:

git status --short

For ordinary tracked-file changes, the first status column describes the index and the second describes the working tree. An unstaged modification appears as M; a staged modification appears as M . Untracked files appear as ??. These distinctions help you choose an operation instead of guessing from a filename. See the official status documentation.

Create a disposable lab

Use Bash or Zsh on Linux or macOS with Git 2.23 or later. Run the sections in order. Pick a new directory name if this one already exists; stop if directory creation fails.

mkdir git-undo-lab && cd git-undo-lab
git init
git config user.name "Git Undo Lab"
git config user.email "git-lab@example.com"
git config commit.gpgsign false
printf 'workers=2\n' > app.conf
git add app.conf
git commit -m "Initial configuration"

The identity and signing settings apply only to this lab repository. The email is an example identity, not an account to contact. The workers setting is an invented configuration value for this exercise, not a recommendation for a real service.

The command sequence below was checked in a disposable repository using Git 2.39.5. Commit hashes and Git’s informational messages will differ on your machine.

Inspect the difference before choosing an undo command

git diff -- app.conf
git diff --cached -- app.conf
git diff HEAD -- app.conf

The first comparison shows working-tree changes relative to the index. The second shows staged changes relative to HEAD. The third compares the working-tree file with HEAD, including its overall difference whether or not parts are staged.

Immediately after the initial commit, all three should be empty. Later, use these views to answer different questions: “What did I edit after staging?”, “What would my next commit contain?”, and “How does this file differ from the committed version?” They are especially useful when a file has both staged and unstaged changes. See the diff reference.

Use restore to unstage or restore a file

Make a deliberate lab edit and stage it:

printf 'workers=3\n' > app.conf
git add app.conf
git restore --staged -- app.conf
git status --short
cat app.conf

The file still contains workers=3, but the change is now unstaged. With --staged, restore uses HEAD by default and updates the index without changing the working-tree file.

The next command discards the lab file’s unstaged edit. Run it only when you want that edit removed:

git restore -- app.conf
cat app.conf

The value returns to workers=2. Without --staged, restore normally copies from the index into the working tree. That distinction matters if the index already contains another version: plain restore does not necessarily recover the HEAD version. Restore does not create a reversing commit or move your branch tip. See the restore reference.

Use soft reset to revise an unpublished local commit

Create a second commit and keep a reference to it:

printf 'workers=5\n' > app.conf
git add app.conf
git commit -m "Set demo worker count to five"
git branch before-reset
git reset --soft HEAD~1
git status --short
git diff --cached -- app.conf

Here, HEAD~1 is the parent commit. Soft reset moves the current branch back while preserving both the index and working-tree content. The change to five workers remains staged, ready to recommit:

git commit -m "Revise the local worker-count change"

This exercise changes local branch history. Do not apply it to shared history without coordinating with collaborators. Other reset forms behave differently: mixed reset also resets the index; hard reset can discard working-tree changes and overwrite untracked files. We do not use hard reset in this lab. A path-specific reset updates the index without moving HEAD. Consult the reset reference before choosing a different form.

Use revert to reverse a commit while preserving history

The lab is now clean. Reverse its latest ordinary commit:

git status --short
git revert --no-edit HEAD
cat app.conf
git log --oneline -3

The value returns to workers=2, and the log includes an additional revert commit. The original change remains in the history. This is generally the appropriate approach when other people already rely on a commit and you want a visible, reviewable reversal.

Reverting can conflict with later changes. If it does, inspect and resolve the conflict before continuing, or use git revert --abort to abandon that revert operation. Merge commits require a deliberate mainline choice and are outside this exercise. See the revert documentation.

Treat the reflog as a recovery aid, not a backup

git reflog --date=iso
git show before-reset:app.conf

The reflog records local reference movements and can help locate an earlier commit after a mistaken branch operation. In this lab, the explicit before-reset reference also lets you inspect the original five-worker version.

A reflog is local and its entries can expire. It is not a complete record of every file edit, and it cannot be relied on to recover content Git never recorded. Keep important work in commits and appropriate backups. Read the reflog reference before attempting recovery in a real repository.

Apply the habit to DevOps work

Before changing a deployment manifest, pipeline file, or automation script, write down the intended outcome: remove an item from the next commit, discard a specific edit, revise a private commit, or reverse an already shared change. Then inspect the relevant diff and choose the smallest operation that achieves it.

Afterward, inspect the result again and run the checks appropriate to that project. A Git operation can restore file content; it does not by itself reverse a database migration, undo a cloud change, or roll back an application already running elsewhere. Those actions need their own operational plan.

For guided practice with repositories and team workflows, explore Network Nuts’ Git Version Control Training. Repeat this lab until you can predict the status and diff before running each command.