Various scenarios of undoing commits in Git discussed.

There are already many very thorough posts about how to undo stuff in Git, for example this one. I will not aim to be more thorough but rather I will just pick out some points I find most frequently used/worth emphasizing. This is essentially some kind of cheat sheet.

  • Undo a unstaged change (“discard” new changes): git restore <file> (previously we use git checkout -- <file>, which behaves the same).
  • Undo a stage (undo git add): git restore --staged <file> (previous we use git reset HEAD <file>, which behaves the same. Take note that none of these actually discards any change made to the file; they only unstage the changes. I have a relevant post that discusses the limitation of this “unstaging” operation).
  • Undo a local commit/going back to a previous commit (undo git commit): git reset <last good commit> (By default this is soft, keeps the working tree changes, add --hard to remove those if desired. Caution! This deletes git history. If you want to keep history use the git revert described below. Personally, I found git reset --hard HEAD~1 very handy)
  • Fix last commit message: git commit -amend -m <correct message>. (It replaces the most recent commit with a new commit that incorporates any staged changes; if nothing is staged, it only rewrites commit message.)
  • Undo a pushed commit: git revert <last good commit> then git push. (It creates a new commit than automatically undoes all changes since the last good SHA. No history deleted. You just now have a new commit on top of all previous but without those changes).