git restore, reset, or revert? Choose the State You Want to Change
Follow one configuration file through Git's working tree, staging area, and history to choose an undo command and verify what it changed.

A file contains the wrong port. That does not yet tell you whether to run restore, reset, or revert. The edit might exist only on disk, it might already be staged, or it might belong to a commit other people have pulled. Choose the state you want to change before choosing the command.
| Intended result | Starting point | Command to consider |
|---|---|---|
| Discard a file’s edits made after staging | Working tree differs from index | git restore -- service.conf |
| Remove a file from the next commit, preserving its current contents | Index differs from HEAD | git restore --staged -- service.conf |
| Move a private branch back one commit while keeping its changes staged | Last commit is local and deliberately being rebuilt | git reset --soft HEAD~1 |
| Record a reversal of a commit without moving existing history backward | Commit is already shared | git revert <commit> |
These commands have other modes. This table deliberately chooses one explicit operation for each problem. The restore, reset, and revert manuals document their wider behavior.
Give the file three different versions
Use Bash in a new disposable directory, with Git 2.23 or newer for restore. The experiment below was checked with Git 2.55.0. It needs no hosting account or remote repository. The local identity settings apply only to this practice repository.
practice_dir=$(mktemp -d)
cd "$practice_dir"
git init -b main
git config user.name 'Practice Learner'
git config user.email 'learner@example.invalid'
printf 'port=8000\n' > service.conf
git add service.conf
git commit -m 'Record baseline'
printf 'port=8001\n' > service.conf
git add service.conf
printf 'port=8002\n' > service.conf
Now inspect all three versions:
git show HEAD:service.conf
git show :service.conf
cat service.conf
git status --short
The committed version is 8000, the index contains 8001, and the file on disk contains 8002. Status reports MM service.conf: there is a staged modification and a separate unstaged modification.
This distinction matters because “restore the file” has a source as well as a destination. You cannot decide what will survive by reading the file alone.
Discard the latest edit, then unstage the earlier one
Read the two diffs before changing anything:
git diff -- service.conf
git diff --cached -- service.conf
The first shows 8001 becoming 8002; the second shows 8000 becoming 8001. To discard only the later working-tree edit:
git restore -- service.conf
cat service.conf
git diff -- service.conf
The file now contains 8001, and the working-tree diff is empty. Plain restore copied the index version to disk. It did not return the file to the committed 8000 version.
To remove the staged change without discarding the file:
git restore --staged -- service.conf
git show :service.conf
cat service.conf
git status --short
The index now contains 8000; the working file still contains 8001. Status has one unstaged modification. If you really intend to replace both versions with HEAD, the explicit form is git restore --source=HEAD --staged --worktree -- service.conf. That discards the uncommitted tracked-file changes for this path; review them first.
For a closer look at the snapshot that a commit uses, see staged versus unstaged changes.
Rebuild a private commit without deleting its changes
Continue the disposable example:
git add service.conf
git commit -m 'Change port'
git branch keep-port-change
git reset --soft HEAD~1
The backup branch names the original commit. The soft reset moves main to its parent while leaving the index and working tree alone. Check the resulting state:
git show HEAD:service.conf
git show :service.conf
cat service.conf
git diff --cached
HEAD contains 8000; both other versions contain 8001. You can now make a new commit from the staged change. A path-based reset, such as git reset HEAD -- service.conf, is a different operation: it resets the index entry without moving the branch.
--hard is not a stronger spelling of --soft. It also updates the index and working tree, and can discard uncommitted tracked-file changes. It is unnecessary for this exercise.
Reverse a shared change with a new commit
Commit the staged port change again, then reverse it:
git commit -m 'Change port deliberately'
git revert --no-edit HEAD
git log --oneline -3
cat service.conf
The log includes the port-change commit and a later reversal. The file returns to 8000. This example uses the latest ordinary commit and a clean working tree; it does not cover merge commits or conflicts caused by later edits.
If a revert conflicts, inspect git status, resolve the relevant files, stage the resolution, and use git revert --continue. Use git revert --abort if you intend to cancel the attempt. Do not assume that reverting an older change restores the whole project to that date.
A reflog can help locate a previous local branch position. It is not a backup of every unstaged edit, and other collaborators do not receive your local reflog. Before an undo in a real project, write down which contents must survive, inspect both diffs, and verify the same three states afterward.
References
- Git restore — restoring index and working-tree contents from a selected source.
- Git reset — branch-moving modes and path-based index updates.
- Git revert — recording reversals and handling interrupted operations.
- Git reflog — local reference-position records and their limits.