Git & Command Line · Lesson 5 of 5
Undoing Things and Team Workflows
Restore, reset, revert, stash and the reflog safety net.
- Advanced
- 15 min read
- 3 objectives
Before this lessonLesson 4: Remotes, GitHub and Pull Requests
What you will learn
- Undo safely
- Use stash
- Recover with reflog
Everyone makes mistakes: a commit in the wrong branch, a bad edit, a message typo. Git gives you many ways to undo, but they behave differently. Knowing which is safe on shared history versus local history keeps you out of trouble.
Mistakes are cheap in Git
The reason experienced developers are relaxed about Git is that almost everything can be undone, as long as it was committed. The trick is choosing the right undo for the situation. Ask two questions: Has it been committed? and Has it been pushed and shared? The answers pick the tool.
- Not committed yet →
git restore(throws away edits). - Committed, not pushed →
git commit --amendorgit reset(rewrites your own history). - Already pushed and shared →
git revert(adds a new commit that cancels the old one; never rewrites shared history).
Discard uncommitted changes
git restore file.txt # throw away edits to a file (cannot be undone!)
git restore --staged file.txt # unstage, keep the edits
git clean -n # preview untracked files that would be removedFix the last commit
git commit --amend -m "Better message" # change message
git add forgotten.txt
git commit --amend --no-edit # add a file to the last commit--amend rewrites the last commit, so only do it before you push.
revert: the safe undo for shared history
git revert creates a new commit that reverses an earlier one. History is preserved, so it is safe to push.
git revert a1b2c3dreset: move the branch pointer
git reset --soft HEAD~1 # undo the commit, keep changes staged
git reset HEAD~1 # undo the commit, keep changes unstaged (--mixed)
git reset --hard HEAD~1 # undo the commit AND delete the changesstash: set work aside
Need to switch branches but your changes are not ready to commit?
git stash push -m "wip login form"
git switch other-branch
# ...do something...
git switch -
git stash list
git stash pop # bring the changes backreflog: your safety net
Git records every place HEAD has been, for about 90 days, even for commits no branch points to. If you think you lost work after a bad reset or a deleted branch, look here.
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# 9f8e7d6 HEAD@{1}: commit: Add checkout page
git reset --hard 9f8e7d6 # jump back to before the mistakeOther useful tools
git cherry-pick <sha>: copy one commit onto the current branch.git bisect: binary search through history to find the commit that introduced a bug.git tag v1.0.0: mark a release.
Team workflow summary
- GitHub Flow: short-lived branches and PRs into
main, deploy from main. Simple and popular. - Trunk-based: very small changes merged to main daily, behind feature flags.
- Git Flow: long-lived develop and release branches. Heavier; suited to versioned releases.
Situation 1: I edited a file and want the old version back
$ git status
modified: index.html
$ git restore index.html # discards the edits (cannot be undone!)
$ git status
nothing to commit, working tree cleanSituation 2: I committed too early or with a typo in the message
$ git commit -m "Add serch box"
$ git commit --amend -m "Add search box" # fixes the last commit message
$ git add forgotten-file.css
$ git commit --amend --no-edit # adds the file to the last commitSituation 3: a bad commit is already on GitHub
$ git log --oneline
9d1e4b7 Break the login page
3f2a91c Create homepage
$ git revert 9d1e4b7 # creates a new commit that undoes it
[main c07be21] Revert "Break the login page"Because revert only adds history, teammates who already pulled the bad commit are not affected, and the story stays honest.
Situation 4: I need to switch tasks but my work is half done
$ git stash # sets your edits aside, working tree is clean
$ git switch hotfix # fix something urgent...
$ git switch main
$ git stash pop # bring your unfinished work backSituation 5: "I lost a commit!"
Git keeps a private diary of everywhere your branch has pointed, called the reflog. Even after a bad reset the commit is usually still there for weeks.
$ git reflog
c07be21 HEAD@{0}: revert: Revert "Break the login page"
9d1e4b7 HEAD@{1}: commit: Break the login page
3f2a91c HEAD@{2}: commit (initial): Create homepage
$ git reset --hard 3f2a91c # jump back to any of those pointsKey takeaways
- Pick the undo by asking: committed? pushed?
restorefor edits,amend/resetfor local commits,revertfor shared ones.stashparks unfinished work;reflogfinds "lost" commits.- Never rewrite history that others have already pulled.
# Write your solution here
