Git path · Undoing safely · Topic 6 of 13

Undo: restore, reset and revert

Not started

Git has three undo commands, and each changes a different set of the three places from the index topic. git restore copies file contents into the working tree or the index and never moves a branch. git reset moves the current branch to another commit and, depending on the mode, also resets the index and the working tree. git revert changes nothing that exists: it adds a new commit that reverses an old one.

Why it matters: Picking the wrong undo command is how people lose work. Each one changes a different combination of working tree, index and branch.

  1. 1restore changes files

    git restore discards working-tree edits; with --staged it unstages. The branch does not move.

  2. 2reset moves the branch

    --soft moves only the branch, --mixed (default) also resets the index, --hard also overwrites the working tree.

  3. 3revert adds a commit

    It makes a new commit that does the opposite of an old one. History is kept, so it is safe on shared branches.

  4. 4Hard means unrecoverable edits

    Uncommitted changes thrown away by reset --hard or restore were never in a commit. The reflog cannot bring them back.

1

How it works

The explanation, with examples you can run.

restore: throw away or unstage edits

git init -q -b main demo && cd demofor n in 1 2 3; do echo "v$n" > notes.txt; git add notes.txt; git commit -q -m "Notes v$n"; doneecho "oops" > notes.txtgit restore notes.txtcat notes.txtecho "draft" > notes.txt && git add notes.txtgit restore --staged notes.txtgit status --short
v3 M notes.txt

git restore <path> copies the index version over the working tree, so oops is gone for good. --staged copies HEAD's version into the index; the draft edit stays on disk, now unstaged. --source=<commit> restores from any commit instead.

reset: move the branch

git restore notes.txtgit log --onelinegit reset --soft HEAD~1git status --shortgit log --oneline
a8c64d8 Notes v3d4cbec6 Notes v246f1e57 Notes v1M  notes.txtd4cbec6 Notes v246f1e57 Notes v1

--soft moved main back to v2. The v3 content is still in the index and on disk, staged (M in the first column), ready to be committed again, perhaps with a better message. Recommit, then try the other two modes:

git commit -q -m "Notes v3 again"git reset -q HEAD~1git status --shortgit commit -q -am "Notes v3 once more"git reset --hard HEAD~1cat notes.txt
 M notes.txtHEAD is now at d4cbec6 Notes v2v2
ModeBranchIndexWorking tree
--softmovedkeptkept
--mixed (default)movedreset to targetkept
--hardmovedreset to targetreset to target

After --mixed the change is still on disk but unstaged ( M). After --hard both are back at v2. The commits that were dropped are not deleted; the reflog topic shows how to get them back. Uncommitted edits overwritten by --hard cannot be recovered.

revert: undo in public

git revert --no-edit HEAD > /dev/nullgit log --onelinecat notes.txt
55df303 Revert "Notes v2"d4cbec6 Notes v246f1e57 Notes v1v1

The new commit reverses v2's change and history shows both. Use revert on any branch others have pulled. Reverting a merge needs -m 1 to say which parent's side to keep.

Which one?

  • Edited a file and want the committed version back: git restore <path>.
  • Staged something by mistake: git restore --staged <path>.
  • Last commit not pushed and you want to redo it: git commit --amend, or git reset --soft HEAD~1.
  • Local commits you want to throw away entirely: git reset --hard <commit> (stash first if anything is uncommitted).
  • A pushed commit is wrong: git revert <commit>.
2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.A bad commit is already on the shared main branch. How do you undo it?
  2. 2.You want to redo the last commit's message and contents, keeping all its changes staged. Which command?
  3. 3.Which command can destroy work that was never committed?

0 of 3 right so far. Get all three to finish this topic.