git stash, reflog and reset: Saving and rescuing changes
In short: With stash you put unfinished work aside, with reset you roll back states, and the reflog helps recover almost any seemingly lost commit.
In more detail: Git stores much more than you think: even after reset --hard, an accidentally deleted branch or a failed rebase you can often rescue everything, as long as you act quickly. A small repertoire suffices.
In Depth
git stash: putting work aside
git stash # put current changes aside
git stash -u # also new (untracked) files
git stash list # list
git stash pop # bring back last stash (and delete)
git stash apply stash@{1} # bring back a specific one (keep)
git stash drop # delete
git stash push -m "experiment" file.txtUseful when you must switch branches quickly without committing. Stashes belong only locally to you; better commit important work into its own branch.
git reset: resetting
git reset --soft HEAD~1: undo the last commit, changes stay staged.git reset HEAD~1(mixed): undo commit, changes stay in the working directory.git reset --hard HEAD~1: discard commit and changes (dangerous!).git restore filediscards changes of a file,git restore --staged fileremoves it from the staging area.- On shared branches better
git revert <commit>than reset: creates a new commit that undoes the change without rewriting history.
git reflog: the safety net
The reflog records where HEAD and branches pointed in the last weeks:
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# e4f5g6h HEAD@{1}: commit: New feature
git reset --hard e4f5g6h # restore old state
git branch rescued e4f5g6h # or save as a new branchThis recovers lost commits after a wrong reset, rebase or deleted branch (by default about 90 days, only in the local repository).
Typical rescues
- Branch deleted by accident:
git reflog, thengit branch name <sha>. - Rebase broken:
git rebase --abortorgit reset --hard ORIG_HEAD. - Committed on the wrong branch:
git branch new, then on the old onegit reset --hard HEAD~1. - File deleted but committed:
git restore --source=<commit> -- file. - Never committed: then Git often cannot help; commit regularly, even unfinished (WIP commits), and tidy up later.
See also: Git, git rebase, git bisect and cherry-pick, Resolving a merge conflict, Push rejected