> ## Content Index
> Fetch the complete content index at: https://debugly.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Recovering Work After a Bad git reset --hard
- URL: https://debugly.dev/recover-work-after-git-reset-hard/
- Published: 2026-03-17T09:10:00.000Z
- Updated: 2026-10-17T05:58:53.000Z
- Description: Your commits are almost certainly still there. Here is how reflog works, what it cannot save, and the recovery path for each case.
- Author: Rohit Bhadani
- Tags: Debugging, Tooling, Engineering Culture

## The short version

```bash
git reflog

```

Find the commit you were on before the reset. Then:

```bash
git reset --hard HEAD@{3}      # or the sha

```

Committed work is recoverable for at least 30 days by default. **Uncommitted work is not**, unless you stashed it or your editor kept local history.

Tested on git 2.47.

## Why committed work survives

Git almost never deletes objects immediately. `git reset --hard` moves a branch pointer and updates the working tree. The commits the branch used to point at are still in the object database, just unreferenced.

The reflog is a per repository log of every position `HEAD` and each branch has held. It is local, it is not pushed, and it is the safety net.

```bash
$ git reflog
a1b2c3d HEAD@{0}: reset: moving to HEAD~3
8e9f0a1 HEAD@{1}: commit: add retry logic to sync worker
4c5d6e7 HEAD@{2}: commit: extract config parsing
9a8b7c6 HEAD@{3}: commit: wip on connection pool
2f3e4d5 HEAD@{4}: checkout: moving from main to feature/pool

```

Everything above `HEAD@{0}` is where you were before. `8e9f0a1` is the commit you thought you destroyed.

Two ways back:

```bash
# move the current branch back
git reset --hard 8e9f0a1

# or inspect first, safer
git checkout 8e9f0a1
git switch -c recovery

```

I would do the second. Creating a branch at the recovered commit means you can look at it before deciding, and you have not moved anything you might need again.

Unreferenced objects are kept for 90 days by default for reachable ones and 30 days for unreachable ones, controlled by `gc.reflogExpire` and `gc.reflogExpireUnreachable`. So you have time, unless something ran an aggressive `git gc --prune=now`.

## Case by case

### Reset away commits on the current branch

Covered above. `git reflog`, find the sha, branch from it.

### Deleted a branch

```bash
git branch -D feature/important

```

The reflog for that branch is gone, but `HEAD`'s reflog still records the last time you were on it:

```bash
git reflog | grep "feature/important"
# 8e9f0a1 HEAD@{12}: checkout: moving from feature/important to main

```

That sha is the branch tip.

```bash
git branch feature/important 8e9f0a1

```

### Amended a commit you needed

```bash
git commit --amend

```

The original is still there:

```bash
git reflog
# 3d4e5f6 HEAD@{0}: commit (amend): fix typo
# 7a8b9c0 HEAD@{1}: commit: add feature

```

`7a8b9c0` is the pre-amend version.

### A rebase went wrong

Rebases record a lot of reflog entries. The useful marker is the one before the rebase started:

```bash
git reflog | grep -n "rebase" | head
# look for "rebase (start)" or "rebase -i (start)"

```

Git also keeps `ORIG_HEAD` pointing at where you were before the last big operation:

```bash
git reset --hard ORIG_HEAD

```

That is the quickest recovery from a bad rebase or merge, and worth remembering because it needs no reflog reading at all.

### Dropped a stash

```bash
git stash drop        # regretted immediately

```

Stashes are commits, so they are recoverable, but they do not appear in the normal reflog. Find dangling commits:

```bash
git fsck --unreachable | grep commit | cut -d' ' -f3 | xargs -n1 git log -1 --oneline

```

Or specifically for stashes:

```bash
git fsck --unreachable |
  grep commit |
  cut -d' ' -f3 |
  xargs -n1 git log --merges --no-walk --format="%H %ci %s" |
  grep -i "WIP on"

```

Then restore:

```bash
git stash apply <sha>

```

### Committed to the wrong branch

Not data loss, and worth including because the panic response is often a hard reset that turns it into data loss.

```bash
git log --oneline -3                # note the shas you want to move
git switch correct-branch
git cherry-pick <sha1> <sha2>
git switch wrong-branch
git reset --hard HEAD~2

```

Do the cherry-picks first, verify, then reset. Reversing that order is how a recoverable mistake becomes an interesting afternoon.

## What you genuinely cannot recover

Being clear about this matters, because most recovery guides are vague about it.

**Uncommitted changes destroyed by `git reset --hard` or `git checkout -- .`** are gone from git's perspective. There is no object, because nothing was ever written to the object database.

**Untracked files removed by `git clean -fd`** are gone. Git never knew about them.

Three things sometimes save you anyway:

**Your editor's local history.** JetBrains IDEs keep a full local history per file, independent of git, and it has saved me more than once. VS Code has Timeline in the explorer sidebar, which keeps recent versions. Check these before concluding the work is lost.

**Files you had added to the index.** If you ran `git add` at any point, the content was written to the object database as a blob even though you never committed:

```bash
git fsck --lost-found
ls .git/lost-found/other/

```

Those are blobs with no filenames. `file` and `head` on each one will identify them. This is the single most underappreciated recovery path, and it works surprisingly often because most people `git add` before they do something destructive.

**Your build output or a running process.** A dev server with the file loaded in memory, a Docker container built five minutes ago, or a `dist/` directory can contain a compiled version of what you lost. Not the source, and sometimes enough to reconstruct it.

## Reading the reflog properly

Time based references are often easier than counting entries:

```bash
git reflog --date=iso
git show 'HEAD@{2 hours ago}'
git diff 'main@{yesterday}' main

```

For a specific branch's history rather than `HEAD`'s:

```bash
git reflog show feature/pool

```

And to see what a commit actually contained before you reset to it:

```bash
git show --stat 8e9f0a1
git diff HEAD 8e9f0a1

```

Always look before you move. The recovery is cheap and a second wrong reset on top of the first is not.

## Making this less likely

**Commit more often, in smaller pieces.** The single best protection. Committed work is recoverable; uncommitted work is not. A messy commit history can be cleaned up later with an interactive rebase, and there is no equivalent cleanup for work that never existed.

I have moved to committing anything I would be annoyed to lose, immediately, with a throwaway message. `wip` is a perfectly good commit message for a commit that will be squashed.

**Use `git stash push` rather than discarding.** `git stash push -m "trying the pool refactor"` costs nothing and is recoverable.

**Prefer `git restore` to `git checkout`** for files. The newer commands split the overloaded behaviour of `checkout` into `switch` for branches and `restore` for files, which makes accidental destruction less likely.

**Enable rerere** so git remembers how you resolved a conflict:

```bash
git config --global rerere.enabled true

```

Not a recovery tool exactly, and it removes the most common reason people abort and redo a rebase.

**Push work in progress branches.** A branch on the remote is a backup that survives your laptop. There is no rule that a pushed branch has to be finished.

**Never run `git gc --prune=now` casually.** It is the one command that turns "recoverable" into "gone". If a repository is large, `git gc` without the aggressive prune is fine and keeps the safety net.

## The general lesson

The reflog is one of a small number of tools that make a class of mistake reversible, and most people learn it exists during the incident where they need it.

It is worth spending ten minutes with it while nothing is wrong. Run `git reflog` on a repository you use, read the last twenty entries, and follow what each operation did. When you next need it you will be reading rather than learning.

---

Published on [debugly.dev](https://debugly.dev/) by [Rohit Bhadani](https://debugly.dev/about/) | Founder of [Krova Cloud](https://krova.cloud/?ref=debugly.dev)