NeuroAgent

How to Recover from git reset --hard HEAD~1

Learn how to recover commits and files lost from git reset --hard HEAD~1 using reflog, remote repositories, and prevention strategies. Complete recovery guide with step-by-step instructions.

Question

How can I undo the changes caused by git reset --hard HEAD~1? Is it possible to recover the commits and files that were removed by this command?

NeuroAgent

When you run git reset --hard HEAD~1, you permanently remove the most recent commit and discard all changes in both the staging area and working directory. Recovery is possible through several methods, primarily using Git’s reflog mechanism, but it requires quick action before Git’s garbage collector permanently deletes the unreferenced objects.

Contents

Understanding What Was Lost

git reset --hard HEAD~1 performs three destructive operations:

  1. Removes the HEAD~1 commit from the current branch
  2. Resets the branch pointer to HEAD~2 (or becomes orphaned if it was the first commit)
  3. Discards all changes in the working directory and staging area that were in the removed commit

The commits and associated files aren’t immediately deleted - they become “dangling” objects that Git’s garbage collector will eventually remove. This creates a recovery window, typically lasting 30 days or until the next garbage collection run.


Recovery Methods

Using Git Reflog

Git’s reflog (reference log) is your primary recovery tool. It records every change to branch heads and commits, even those not referenced by any branch.

bash
# View the reflog to find your lost commit
git reflog

# Look for an entry like:
# HEAD@{0}: reset: moving to HEAD~1
# HEAD@{1}: commit: Your commit message here

# Once you find the lost commit hash, restore it
git checkout <lost-commit-hash>

# Or create a new branch from the lost commit
git branch recovered-branch <lost-commit-hash>

Important: The reflog only exists locally and isn’t shared with other repositories. Recovery must be done on the machine where the reset was performed.

Finding Commits in Other Branches

If the commit exists in other branches or was pushed to a remote repository, recovery becomes much simpler:

bash
# Check if the commit exists in other local branches
git log --all --oneline | grep <commit-message-or-hash>

# If found, cherry-pick or merge the commit
git checkout <branch-with-commit>
git cherry-pick <commit-hash>

# Or create a new branch from the commit
git branch recovered-branch <commit-hash>

Recovering from Remote Repositories

If the commit was pushed to a remote repository before the reset:

bash
# Fetch the latest from remote
git fetch origin

# Check remote branches for the commit
git log --remotes --oneline | grep <commit-message>

# If found, create a local branch tracking the remote
git checkout -b recovered-branch origin/<remote-branch>

# Or force push to restore (use with caution)
git push --force-with-lease origin recovered-branch

Prevention Strategies

The best recovery strategy is prevention:

  1. Use git reset --soft or --mixed instead of --hard when you want to undo commits but keep changes
  2. Create backup branches before major operations:
    bash
    git backup-branch=$(git rev-parse --short HEAD)-backup
    git branch $backup-branch
    
  3. Use interactive rebase for safer commit manipulation
  4. Configure longer reflog retention:
    bash
    git config gc.reflogExpire never  # Keep reflog indefinitely
    git config gc.reflogExpireUnreachable never
    
  5. Regular backups of important repositories

Step-by-Step Recovery Guide

Here’s a comprehensive recovery workflow:

1. Check the Reflog Immediately

bash
git reflog

Look for the entry right before the reset operation. Note the commit hash and message.

2. Verify the Commit Still Exists

bash
git fsck --unreachable | grep commit

This shows if Git still has the commit objects in its database.

3. Create a Recovery Branch

bash
git checkout -b recovered-branch <commit-hash-from-reflog>

4. Restore Files to Working Directory

If you need the files in your current working directory:

bash
git checkout <commit-hash> -- path/to/file1 path/to/file2

5. Merge Back to Original Branch (Optional)

bash
git checkout original-branch
git merge recovered-branch

6. Clean Up (Optional)

Once recovered, you can remove the temporary branch:

bash
git branch -D recovered-branch

When Recovery Is Not Possible

Recovery becomes impossible when:

  1. Garbage collection has run - Git has cleaned up unreferenced objects
  2. No local reflog entry exists - The reflog was cleared or expired
  3. No other references exist - The commit wasn’t in remote branches or tags
  4. The working directory was modified after the reset

In these cases, you may need to rely on:

  • Manual reconstruction from memory or other sources
  • File system recovery tools (if files still exist on disk)
  • Backup repositories or version control mirrors

Conclusion

Recovering from git reset --hard HEAD~1 is often possible if you act quickly, but prevention is always better than recovery. Key takeaways:

  1. Use git reflog immediately after any accidental reset to find lost commits
  2. Verify commit existence with git fsck before attempting recovery
  3. Create backup branches before major destructive operations
  4. Configure Git settings to extend reflog retention for better recovery chances
  5. Consider safer alternatives like git revert for undoing commits without losing history

The best approach is to develop good Git habits that prevent accidental loss in the first place, but when accidents happen, the reflog provides a reliable safety net for recovery.

Sources

  1. Git Documentation - git-reset
  2. Git Documentation - git-reflog
  3. Atlassian Git Tutorial - Undoing Changes
  4. GitHub Docs - Recovering from accidental reset