Reset vs revert: two ways to undo, one of them destructive
Reset pretends the commit never happened. Revert admits it happened and undoes it in public.
You pushed something broken. Both commands get the bad change out of your working tree. Only one of them is safe to run on a branch other people have.
Undoing commit D, two ways
1 / 3git reset --hard
Four commits. D is the one you regret.
git revert
Identical starting point. D is the tip of main.
D is the bad commit and it is currently the tip of main. HEAD points at main, main points at D.
The reset flag that actually matters
reset moves the branch pointer either way. The flag only decides what happens
to the changes those commits contained:
| Flag | Branch pointer | Staging area | Your files |
|---|---|---|---|
--soft | moves back | keeps the changes staged | untouched |
--mixed (default) | moves back | unstaged | untouched |
--hard | moves back | discarded | discarded |
--soft is the one to reach for when you just want to recommit the same work
differently, squashing three messy commits into one, for example. --hard is
the only variant that can lose uncommitted work, and it is the one people
usually mean when they say reset is dangerous.
Which one to use
The deciding question is never "how bad was the commit". It is has anyone else seen it?
- Only on your machine? Either works.
resetgives a tidier history. - Already pushed to a shared branch?
revert, every time. Reset would require a force push, and a force push on a branch your team pulls is how people lose commits they had already based work on.
Remember this
- 1Reset moves a pointer. Revert adds a commit. That is the entire difference. Everything else follows from it.
- 2Pushed already? Use revert. Reset on a shared branch means a force push, and a force push can destroy other people's work.
- 3A reset commit is not deleted immediately: git reflog still knows its SHA, so an accidental reset --hard is usually recoverable.