When a commit or changes vanish in your Git repository, knowing how Git tracks your work can make the difference between frustration and a quick recovery. Four core concepts—reflog, detached HEAD, stash, and the index—equip you to locate and restore work that might otherwise seem gone.
Using the Reflog to Find Lost Commits
Git keeps a local record called the reflog, which logs every position your HEAD and branches have referenced. Each commit, checkout, reset, rebase, or merge adds an entry like HEAD@{2} to this log. If a hard reset or rebase removes a commit, the reflog helps you find the earlier commit reference. To recover, run:
git reflog # find the line from before the mistake git branch rescued # put a branch on it so it can't get lost
The reflog exists only in your local repository clone and does not sync with remotes. Entries in the reflog act as a recovery tool after operations such as reset, rebase, branch movement, and checkout. Still, the reflog does not serve as a permanent archive of every commit ever made. By default, entries for reachable commits usually last about 90 days, while unreachable commits may expire after roughly 30 days. These timeframes depend on your Git configuration and can be adjusted by repository administrators. Maintenance or garbage collection can remove unreachable objects after their expiration, so the actual recovery window depends on repository settings, Git version, and maintenance routines. For precise details, check the Git project documentation.
Understanding Detached HEAD State
Checking out a specific commit, tag, or remote-tracking branch puts Git into a detached HEAD state. In this mode, HEAD points directly to a commit, not a branch name. This state is often used for reviewing history or testing changes without moving an existing branch. Commits made in a detached HEAD state stay in the repository’s object database, but no branch reference will move forward to keep them. To avoid losing track of these commits, create a new branch at the detached commit:
git switch -c keep-this-work
The older command for this is git checkout -b keep-this-work. Run this command while the desired detached commit is checked out, or create the branch by naming that commit after switching elsewhere. Creating a branch reference does not copy the commit’s contents; it keeps the commit reachable through a named reference, as outlined in the Git project documentation.
Saving Changes with Git Stash
The git stash command lets you temporarily set aside uncommitted changes, returning your working directory and, by default, the index to a clean state relative to HEAD. A stash can include changes to tracked files in the working tree and staged changes in the index. To stash your changes, run:
git stash # staged and unstaged changes to tracked files git stash list # see saved stashes git stash pop # reapply the newest stash and remove it from the list
Untracked or ignored files are not included in the stash unless you use options like --include-untracked or --all. Stash entries are stored under the local refs/stash reference and remain local to your repository, so they are not pushed to a remote. Treat stashes as temporary storage, not as a replacement for committed backups. When restoring a stash, use git stash apply to keep the stash entry, or git stash pop to apply and remove it if successful. Applying a stash can cause merge conflicts, especially if the current branch has changed since the stash was created. It is safer to review entries with git stash list and git stash show before applying. If a stash entry is dropped too soon, recovery may still be possible through the reflog or by checking dangling objects before garbage collection removes them.
The Staging Area (Index) and How It Works
Git's staging area, or index, is a snapshot of what will go into your next commit. The index lives in .git/index and holds a complete tree of files as they appear when you run git add. The index stands apart from both the current commit, shown by HEAD, and the working directory, where you edit files. Commands like git add update the index, while git reset can change the index without always affecting working-tree files, depending on the reset mode. If you change a file after staging it, the staged version stays the same until you add it again. This is why git status can show a file as both "staged" and "modified." To compare changes, use:
git diff # working directory vs index git diff --staged # index vs last commit
Understanding this three-state model—HEAD, index, and working tree—matters because an apparent loss may involve only staged data, only unstaged data, or the committed history. The Git project documentation covers these concepts in more technical detail.
Best Practices for Safe History Rewrites
Before running commands that rewrite history, such as reset, rebase, or commit --amend, check your current status with git status and review recent commits using git log --oneline -5. If something goes wrong, you can find the commit you need in the reflog and recover your work. For full guidance, see the official Git documentation and maintenance guides.
