Programming and IT
git reset
git reset moves the current branch pointer to another commit. How much your work suffers depends on one flag — `--soft` touches nothing but history, `--mixed` clears the index, `--hard` rewrites the files on disk. The third mode is the one Git command that destroys unsaved work for good.
In this article
The three areas the command moves#
To stop mixing up the modes, keep three layers in mind.
- History — where the branch pointer is, and
HEADwith it. - Index — the draft of the next commit, whatever went through
git add. - Working copy — the files in the folder that are open in your editor.
The command always moves the first layer. The rest depends on the flag:
| Flag | History | Index | Files on disk |
|---|---|---|---|
--soft |
moves | untouched | untouched |
--mixed (default) |
moves | reset | untouched |
--hard |
moves | reset | overwritten |
The first two modes are safe: your changes stay in the files; only the way Git sees them changes. The third wipes edits that are not in any commit. Nothing can bring them back — not the reflog, not the trash.
Syntax#
HEAD~1 means "the parent of the current commit", HEAD~3 means "three commits
back". You can put any hash in its place.
Example: redo the last commit#
You committed too early: forgot a file, wrote a poor message, left a debug line in. Remove the commit while keeping all the work staged:
## main
History is one commit shorter, and nothing was lost. When you only need to add a
file or fix the message, there is a shorter route — git commit --amend, covered
among the ways to undo a commit.
Example: unstage something you did not mean to add#
The file left the commit draft and became untracked again; its contents on disk
did not change. The modern synonym for this action is git restore --staged .env;
it reads more clearly and cannot accidentally move a branch. To keep such files
out for good, add them to .gitignore.
The dangerous mode: --hard#
The edit in invoice.py is destroyed. Not "moved", not "stashed" — it no longer
exists anywhere, because it never made it into Git's object database. The same
happens to every unsaved change in every file if you run the command without a
path.
Three habits that remove nearly all the risk:
- before
--hard, always look atgit status -s— if there are lines, stash them first (git stash push -m "just in case", see git stash) or commit them; - to roll back a single file, use
git restore <file>rather than resetting the whole branch; - do not paste
--hardfrom the internet without looking: most of the time where people recommend it,--softor--mixedwould do.
What to do if commits have disappeared#
Here is the good news: commits, unlike unsaved edits, can almost always be brought back. They were not deleted; nothing points to them any more.
The reflog keeps every position of HEAD — several weeks by default, and entries
for commits that became unreachable live for at least thirty days. Find the line
from before the unlucky reset and move the branch back to it. If you would rather
not move the current branch, create a new one at the commit you found:
git switch -c rescue 91b0d3f.
reset or revert#
The difference is who will see the undo.
git reset removes a commit from the branch: it is no longer in the history. That
is fine while the commit lives only on your machine. After it has been pushed,
such a reset needs a forced push, and git push --force wipes whatever teammates
have pushed in the meantime — if you cannot avoid it, use
git push --force-with-lease, which refuses to work when something unexpected
has appeared on the server.
git revert does not touch existing history; it adds a new commit with the
opposite changes. It goes out with an ordinary git push, gets in nobody's way and
is therefore the only right way to undo something that has already reached a
shared branch. Remember the pair: private — reset, shared — revert. The same line
runs through rebasing.
Step-by-step plan
- See what is unsavedgit status -s before any reset: the lines in the output are what can disappear.
- Choose the mode--soft to redo a commit, --mixed to rebuild the index, --hard only with a clean status.
- Pick the targetHEAD~1, a commit hash or origin/main; check your choice with git log --oneline.
- Run it and checkAfter the reset, git status -s and git log --oneline again: the expected tip and the expected files.
- If you missedgit reflog, find the line before the reset and go back — commits are recoverable, unsaved edits are not.
Start learning this in your own space
The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.
Check yourself
1.Which git reset mode destroys uncommitted edits in your files?
2.A commit has already been pushed to a shared branch and must be undone. What do you choose?
3.What does git reset --soft HEAD~1 do?
4.You reset the branch two commits back by mistake and need those commits. Where do you start?
Sources
-
git reset referenceThe modes explained with state tablesfree
-
Pro Git: Reset DemystifiedA detailed chapter with diagrams of the three areasfree
-
git reflog referenceHow to find a commit after a bad resetfree
Was this helpful?