Commits Disappeared After a Rebase

Your commits vanished after git rebase. Recover them from the reflog in under two minutes with no data loss.

You ran git rebase main on your feature branch, hit a conflict halfway through, pressed Ctrl-C or ran git rebase --abort, and now git log --oneline only shows the base branch commits — your five working commits are nowhere to be seen. Or you completed the rebase successfully but the branch now points to a single “squashed” commit instead of the three separate ones you expected. Commits are almost never truly deleted by a rebase; Git stores every intermediate state in the reflog for at least 90 days. This guide shows you how to find those commits, verify they contain your work, and restore the branch to any point in that history.

Common causes

Ordered by hit rate, highest first.

1. Interactive rebase with drop or squash collapsed commits unintentionally

You ran git rebase -i HEAD~5, accidentally hit d on a line you meant to keep, or used squash when you wanted pick. The dropped commits still exist as dangling objects.

How to spot it: git reflog show HEAD | head -20 — you will see an entry like HEAD@{3}: rebase (finish): returning to refs/heads/feature followed by the last SHA before the rebase started.

2. git rebase --abort left the branch on the pre-rebase state, but --abort itself was run after the branch pointer moved

Some Git versions update ORIG_HEAD before aborting, leaving the branch pointer one commit behind where you expect it.

How to spot it: git log ORIG_HEAD..HEAD shows no output (same SHA) but git log HEAD..ORIG_HEAD shows commits you expected to keep.

3. Rebase against the wrong base moved commits “out of range” of the default log

If you rebased a 10-commit branch onto a SHA that is already an ancestor, Git may declare all 10 commits “already applied” and drop them silently.

How to spot it: Run git log --oneline BASE..ORIG_HEAD (replace BASE with the SHA you rebased onto). If it shows commits but they’re not on the branch, they were deemed “already applied.”

4. git pull --rebase auto-resolved conflicts by dropping your local commit

When pull --rebase encounters a conflict that matches a remote commit exactly, it considers your commit “already applied” and removes it.

How to spot it: Count commits before and after. git reflog | grep "rebase" will show the pre-rebase HEAD SHA.

5. Branch was force-pushed by a teammate after your rebase

Your local reflog still shows your commits, but the remote branch now points elsewhere, making it look like your commits vanished when you git fetch.

How to spot it: git log HEAD..origin/feature is non-empty and shows commits you never authored.

6. git rebase --onto used incorrect range arguments

git rebase --onto newbase oldbase branch — if oldbase was specified incorrectly, a different range of commits was moved, and some were left as dangling objects.

How to spot it: git fsck --lost-found lists dangling commit objects. Check them with git show <sha>.

Shortest path to fix

Step 1: Find the pre-rebase SHA in the reflog

git reflog --date=iso | head -30

Look for the line just before rebase (start). The SHA in the left column is your branch pointer immediately before the rebase touched anything. Note it down — call it PREBASE_SHA.

Step 2: Create a recovery branch pointing to that SHA

git branch recovery/feature-prebase PREBASE_SHA

Do not reset your current branch yet. Verify the recovery branch has your commits:

git log --oneline recovery/feature-prebase | head -10

Step 3: Verify the commits contain your actual work

git diff recovery/feature-prebase main -- src/

Confirm you see your changes, not just rebase metadata.

Step 4: Reset your feature branch to the recovery point

# Only after confirming Step 3 shows the right diff
git checkout feature
git reset --hard recovery/feature-prebase

Step 5: Redo the rebase carefully if you still need it

# Use --keep-empty to preserve intentionally empty commits
git rebase main --keep-empty

If conflicts appear, resolve each one and run git rebase --continue rather than --abort.

Step 6: Push the restored branch

# Force push is required because history was rewritten
git push --force-with-lease origin feature

--force-with-lease refuses the push if someone else pushed to the branch since your last fetch, preventing accidental overwriting.

Prevention

  • Always note ORIG_HEAD before any rebase: git log ORIG_HEAD -1 --oneline right after a rebase completes.
  • Run git rebase --interactive with a count, not a branch name when unsure of the range: git rebase -i HEAD~3 is safer than git rebase -i main.
  • Set rebase.missingCommitsCheck = error in your git config so interactive rebase errors out if you accidentally delete a pick line.
  • Use --force-with-lease instead of --force on every push; it prevents overwriting others’ work and alerts you when the remote has unexpected commits.
  • Configure a 30-day minimum for reflog expiry: git config --global gc.reflogExpire 90.
  • After any complex rebase, immediately tag the old and new tips: git tag backup/before-rebase ORIG_HEAD.
  • For shared branches, prefer merge commits over rebase to avoid rewriting public history.

FAQ

Q: The reflog is empty on a freshly cloned repo — how do I recover commits? A: The reflog is local only. If you cloned freshly and the remote branch was force-pushed, the original commits may only exist if someone else’s clone still has them. Ask teammates to run git reflog show origin/feature on their machines.

Q: I used git rebase --onto and the commits are nowhere in the reflog. How is that possible? A: They are in the reflog, but under a different reference. Run git reflog show --all | grep "your commit message snippet" to find them across all refs.

Q: Can I recover commits after git gc ran? A: If gc ran and the commits were already unreferenced, they may be gone. Check git fsck --lost-found — Git writes dangling commits to .git/lost-found/commit/. Inspect each SHA with git show.

Q: Is git reset --hard to ORIG_HEAD always safe after a rebase? A: It is safe if you run it before the next operation that overwrites ORIG_HEAD (such as another merge or rebase). Always confirm git log ORIG_HEAD -1 shows what you expect before the reset.

Tags: #git #version-control #Troubleshooting