Skip to content

Meet Graphite Agent — your collaborative AI reviewer, built right into your PR page.

Read more

Recovering lost commits with git reflog

Greg Foster
Greg Foster
Graphite software engineer
Try Graphite


Note

This guide explains this concept in vanilla Git. For Graphite documentation, see our CLI docs.


Table of contents

Git's reference logs (reflogs) are a lifesaver when you think you've lost commits. This guide will show how to use git reflog to recover lost work in various scenarios. It assumes you know basic Git (branches, commits, reset, rebase) and provides step-by-step examples for local and remote recovery.

A reflog is essentially a log of every move the Git HEAD has made in your local repository. Every commit, checkout, reset, or rebase updates the HEAD and gets recorded in the reflog. In other words, reflog records when branch tips and other refs were updated in the local repo. This is extremely useful because even if a commit is “lost” (no branch or tag pointing to it), its reference may still exist in the reflog, allowing you to retrieve it.

Key points about reflog:

  • Reflog is local: each repository has its own reflog; it isn’t pushed to remotes. That’s why you can recover commits you lost locally, but you won’t see reflog entries on Git hosting services.
  • Reflog entries are indexed like HEAD@{0}, HEAD@{1}, etc., where {0} is the latest state and higher indices go back in time. You can use these in Git commands (for example, HEAD@{1} refers to the previous HEAD).
  • By default, reflog keeps history for a limited time (90 days for normal entries, 30 days for those with no refs) before older entries expire (more on this in tips at the end).

Let’s say you ran git reset --hard HEAD~1 and realized you reset away a commit you still needed. The branch pointer has moved, but the commit isn’t truly gone – it’s just orphaned. You can get it back:

  1. Find the lost commit in the reflog: Run git reflog to list recent history. Look for the entry just before the reset. For example, you might see:

    Terminal
    $ git reflog
    54ad9f0 HEAD@{0}: reset: moving to HEAD~1
    b921d4c HEAD@{1}: commit: Fix login bug

    Here HEAD@{1} (commit b921d4c) is the commit that was “lost” by the reset. Reflog shows that HEAD moved from b921d4c to an earlier commit.

  2. Restore the commit: You have a couple of options to recover the commit:

    • Reset back to it: Use git reset --hard <commit-hash> to move the branch HEAD back to the lost commit. In our example, git reset --hard b921d4c would put the branch back to the Fix login bug commit. (Be careful: this will discard any new uncommitted changes on your working directory.)

    • Create a new branch at that commit: If you don’t want to disturb the current branch’s state, create a new branch from the commit:

      Terminal
      git checkout -b recovered <commit-hash>

      This makes a new branch pointing to the lost commit, allowing you to inspect or merge it as needed.

The commit is now recovered on your local repo. You can continue working or merge it back into your main line of development.

Rebases rewrite commit history, so it’s easy to drop or alter commits by accident. If a rebase went wrong, git reflog can help you undo it:

  1. Identify the pre-rebase commit: Find the commit that was at the tip of your branch before the rebase. Run git reflog and look for entries related to the rebase. Often, you’ll see an entry like HEAD@{N}: rebase:... or a checkout indicating where HEAD was before. That commit hash is the last good state before the rebase. (If multiple rebases or complex changes happened, find the point just before things went awry.)

  2. Reset the branch to the old commit: Once you have the commit hash (let’s call it <old-commit>), do:

    Terminal
    git reset --hard <old-commit>

    This brings the branch back to the state before the rebase. All the original commits will reappear as they were before the rebase.

  3. Alternative – cherry-pick missing commits: If the rebase dropped specific commits that you want to keep (and you don’t want to completely undo the rebase), you can cherry-pick those commits onto the current branch. First, use git reflog (or even git log --all) to locate the hashes of the missing commits, then run git cherry-pick <hash> for each to reapply them on your branch.

Maybe you deleted a branch and then realized it had commits you still need. If the branch was deleted, its commits might not be referenced by any branch now – but if they were recently active, you can likely recover them with reflog:

  1. Find the branch’s last commit: When you delete a branch, Git often prints the commit SHA that the branch was at. If you have that from the terminal output, note it. If not, use reflog to find it:

    • If you had checked out that branch or merged it recently, run git reflog (which shows HEAD history) or git reflog --all to search for the branch’s commits. Look for the branch name or commit message in the reflog output. Each branch has its own reflog too, but once deleted, you might rely on HEAD’s reflog or --all to track it down.
    • You can also try git log --all --grep='<commit message fragment>' if you remember part of a commit message, to locate the commit.
  2. Recreate the branch at that commit: Once you have the commit hash (e.g. abc1234), run:

    Terminal
    git checkout -b <branch-name> abc1234

    This creates a new branch pointing to the recovered commit. The branch is now restored with all its commits intact.

  3. Push to remote if needed: If the branch was also on a remote and you want to restore it there, push the new branch: git push origin <branch-name>. (If the remote branch was deleted and you want to reinstate it, ensure collaborators know – especially if it was deleted intentionally after merging.)

Recovering lost commits on a remote (e.g. GitHub or GitLab) often comes into play after an accidental git push --force that overwrote history. The remote server itself doesn’t have reflog accessible to you, but your local clone does. Here’s how to get back a commit that disappeared from a remote branch:

  1. Find the commit in your local reflog for the remote branch: Your local repo keeps track of where the remote branch pointers were when you last fetched or pushed. Use:

    Terminal
    git reflog show origin/<branch-name>

    For example, to recover a commit lost on origin/main, run git reflog show origin/main. This will show the update history of your tracking branch. You should see an entry for the force-push; the line before it will have the old commit hash that was on origin/main before the push.

  2. Checkout the lost commit (optional verification): Once you identify the commit hash that was lost, it’s wise to check it out to verify its contents. For example:

    Terminal
    git checkout <lost-commit-hash>

    This puts you in a detached HEAD at that commit. You can inspect the code to confirm this is indeed the commit you want to restore.

  3. Restore the remote branch: There are a couple of ways to put this commit back on the remote:

    • Force-push the commit to the original branch: If you want origin/<branch-name> to go back to that commit, you can push it directly. For example:

      Terminal
      git push origin <lost-commit-hash>:<branch-name> --force

      This tells Git to update the remote branch to the specified commit (the same effect as a force push from that commit). After this, collaborators should pull or reset to this restored history as needed.

    • Push as a new branch (safer): If you prefer not to rewrite the remote branch forcefully (for example, if new commits were added after the bad push and you want to preserve them), you can push the recovered commit as a new branch:

      Terminal
      git checkout -b recovered-branch <lost-commit-hash>
      git push origin recovered-branch

      This way, the lost commit is on the remote in a separate branch. You can then decide how to integrate it (merge, cherry-pick, etc.) without clobbering others’ work.

In either case, the important part is that the commit is no longer lost – your reflog helped retrieve it. If the intention is to undo a mistake, you’ll likely use the force-push method to put the history back as it was.

  • Reflog is local and temporary: The reflog exists only in your local .git directory. You can’t fetch another person’s reflog or push yours to a server. This also means if you clone a fresh repo, you won’t have the reflog history of the original.
  • Entries expire and commits can vanish: Reflog entries expire after a time (by default, 90 days for normal entries, and 30 days for those that became unreachable). After that, or after a garbage collection, orphaned commits might be cleaned up permanently. So act relatively quickly when you need to recover something. (Also, avoid running git gc until you’ve recovered the commits you need.)
  • Use new branches for safety: When in doubt, recover lost commits on a new branch rather than immediately resetting HEAD of a main branch. This allows you to review and test before affecting your team’s main history. You can always merge or rebase the recovered commits back once you’re confident.
  • Good commit messages help: Since reflog shows commit messages, having descriptive commit messages makes it easier to spot the right commit in a sea of reflog entries. For example, seeing “Fix login bug” in the reflog is quicker to identify than an ambiguous message.
  • Prevention and backups: While reflog is great for recovery, it’s best to avoid needing it. Be cautious with destructive commands like reset --hard and push --force (use them sparingly and with purpose). For critical branches, consider using protected branches or backup solutions if appropriate. And always ensure your work is pushed or backed up somewhere if it’s important.

Git’s reflog is an indispensable safety net for undoing mistakes. With the steps above, you can confidently recover commits from resets, rebases, branch deletions, and even remote overwrites.

Built for the world's fastest engineering teams, now available for everyone