You ran git reset --hard. Here's how to get your work back

The specific feeling of running git reset --hard and watching an afternoon vanish is one almost every engineer has had exactly once, and then never forgets. The good news is that git usually still has your work. The bad news is that finding it requires knowing which of several unrelated mechanisms applies to your particular disaster.

This is the practical guide, ordered by what actually happened to you.

You committed, then reset --hard past it

This is the recoverable case. Your commits still exist as objects; only the branch pointer moved. The reflog remembers where it was:

git reflog
# find the entry just before the reset, e.g. HEAD@{3}
git reset --hard HEAD@{3}

If you'd rather inspect before committing to it, git show HEAD@{3} or git checkout -b rescue HEAD@{3} gets you a branch to look at safely.

You never committed — the changes were only in the working tree

Here the news is worse. reset --hard overwrites tracked files with the committed state, and uncommitted changes that were never staged are simply gone from git's perspective. Two things sometimes save you:

  • Your editor's local history. JetBrains IDEs keep a Local History; VS Code has Timeline. Both frequently hold the last few hours and are the most common successful recovery route.
  • Staged-but-not-committed content. If you had run git add, the content is in the object database as a dangling blob: git fsck --lost-found then read the files in .git/lost-found/.

You dropped or cleared a stash

Stashes are commits, so they survive being dropped until garbage collection:

git fsck --unreachable | grep commit | cut -d' ' -f3 | xargs git log --merges --no-walk
# or, more simply
git fsck --unreachable | grep commit
git show <sha>      # inspect candidates
git stash apply <sha>

You deleted a branch that was never pushed

The reflog is per-branch, and deleting the branch deletes its reflog — so git reflog alone won't show it. You're back to git fsck --unreachable and reading through dangling commits by hand.

A rebase or merge resolution went wrong

git rebase --abort works while the rebase is in progress. Once it has finished and you dislike the result, you're in reflog territory again: ORIG_HEAD points at where you were before the rebase started, so git reset --hard ORIG_HEAD is usually the fastest undo. If you'd already resolved conflicts by hand and lost that work, it is gone — conflict resolutions are never stored anywhere until they're committed.

The pattern underneath all of this

Notice what these have in common. Five different accidents, five different recovery mechanisms — reflog, ORIG_HEAD, fsck for dangling blobs, fsck for unreachable commits, editor local history — and you must correctly diagnose which category you're in before you can begin. Some cases are trivial. Some are unrecoverable. Nothing tells you which one you're in.

That isn't a flaw in git's implementation; it's a consequence of the reflog being a log of where branches pointed rather than a log of what you did. Operations that don't move a ref leave no trace, which is precisely why uncommitted work and hand-resolved conflicts fall through the floor.

What it looks like when the log records operations instead

This is the problem kal was designed around. Every mutating operation — snapshot, merge, reset, branch delete, tag, even a previous undo — appends an entry recording the complete state of every branch and tag before and after. Recovery isn't a diagnosis followed by the right incantation; it's one command:

kal ops     # every operation, with before/after state
kal undo    # reverse the last one
kal undo 7  # or a specific one

Two properties follow from that design and matter more than the syntax. Snapshots are never deleted, so undo is itself an operation you can undo — pressing it twice returns you exactly where you started. And garbage collection is aware of the log, so it will not prune an object that any past operation could still need. The safety net has no holes in it, which is a different claim from "there is usually a way."

What to do right now, in git

If you're reading this mid-incident: don't run anything else destructive, especially not git gc, and work through the sections above in order. Objects survive roughly two weeks by default, so you have time.

If you're reading it calmly: commit more often than feels necessary. Almost every unrecoverable case in this article is unrecoverable for the same reason — the work was never committed. A cheap checkpoint is the difference between an inconvenience and an afternoon.

Try kal on a repository you already have

kal runs alongside git — kal init inside an existing repo changes nothing until you ask it to. Snapshots record intent and human-vs-AI authorship, every operation is undoable, and kal git sync mirrors everything back into git.

Install kal 5-minute tour