509

First, got "your branch is ahead of origin/master by 3 commits" then my app has reverted to an earlier time with earlier changes.

How can I get what I spent the last 11 hours doing back?

P i
  • 29,020
  • 36
  • 159
  • 267
Elias7
  • 12,285
  • 13
  • 35
  • 35
  • Did you already look at http://stackoverflow.com/questions/277077/why-is-git-telling-me-your-branch-is-ahead-of-origin-master-by-11-commits-a or http://stackoverflow.com/questions/2432579/git-your-branch-is-ahead-by-x-commits or http://stackoverflow.com/questions/2342618/git-your-branch-is-ahead-of-origin-master-by-3-commits ? – Mikel Apr 11 '12 at 03:07

9 Answers9

1114

git reflog is your friend. Find the commit that you want to be on in that list and you can reset to it (for example:git reset --hard e870e41).

(If you didn't commit your changes... you might be in trouble - commit early, and commit often!)

Amber
  • 507,862
  • 82
  • 626
  • 550
  • So the problem actually occurred when I tried to commit... git reflog returns ": HEAD@{0}: checkout: moving from following-users to ma....HEAD@{1}: commit: yo.... HEAD@{2}: commit: updated a ton....HEAD@{3}: checkout: moving from master to following-u...how can I revert back to one of those last three? – Elias7 Apr 11 '12 at 03:14
  • 24
    Take a look at `git log HEAD@{1}`. If that looks like the right series of commits, then you can `git reset HEAD@{1}`. – Amber Apr 11 '12 at 03:21
  • 16
    Only if the codes are staged (using git add), they are kept in git and can be found back easily using commands like `git fsck --lost-found`. – Landys Feb 13 '17 at 12:29
  • 9
    Accidentally dropped a commit I should have kept when rebasing. This totally saved me from redo-ing a couple hours worth of work. – josephting Jan 10 '19 at 06:30
  • Be careful using `--hard`. [Uncommitted changes will be lost](https://stackoverflow.com/questions/24568936/what-is-difference-between-git-reset-hard-head1-and-git-reset-soft-head). – young_souvlaki Jul 20 '20 at 20:54
  • 3
    Do lost commits get auto-deleted after a certain period of time? – TheTechRobo the Nerd Sep 04 '20 at 23:47
  • 4
    @TheTechRobo36414519 git-gc eventually cleans up old reflog entries, and once nothing references a commit its objects will eventually be cleaned up too. The conditions under which the reflog is cleaned up can be set via git-gc's config options https://git-scm.com/docs/git-gc#Documentation/git-gc.txt-gcreflogExpire (at the time of this comment, the default expiry for reflog entries is 90 days for commits which are reachable, and 30 days for commits which are unreachable from current tips). – Amber Sep 09 '20 at 00:50
  • My particular issue was that I committed my changes to a feature branch I wasn't using anymore and then, after switching back to `main` and pulling an update of the repo, those commits were seemingly gone. For me, merging my committed changes from the feature branch into `main` fixed the issue. – Michael Murphy Jul 28 '22 at 06:55
  • You saved my life, this command is OP – Ivan_OFF Jul 25 '23 at 07:25
195

Before answering, let's add some background, explaining what this HEAD is.

First of all what is HEAD?

HEAD is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD at any given time (excluding git worktree).

The content of HEAD is stored inside .git/HEAD and it contains the 40 bytes SHA-1 of the current commit.


detached HEAD

If you are not on the latest commit - meaning that HEAD is pointing to a prior commit in history it's called detached HEAD.

Enter image description here

On the command line, it will look like this - SHA-1 instead of the branch name since the HEAD is not pointing to the tip of the current branch:

Enter image description here

Enter image description here


A few options on how to recover from a detached HEAD:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

This will checkout new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point, you can create a branch and start to work from this point on.

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

You can always use the reflog as well.
git reflog will display any change which updated the HEAD and checking out the desired reflog entry will set the HEAD back to this commit.

Every time the HEAD is modified there will be a new entry in the reflog

git reflog
git checkout HEAD@{...}

This will get you back to your desired commit

Enter image description here


git reset --hard <commit_id>

"Move" your HEAD back to the desired commit.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Note: (Since Git 2.7) you can also use the git rebase --no-autostash as well.

git revert <sha-1>

"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be committed while the original commit will remain in the history as well.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

This schema illustrates which command does what.
As you can see there, reset && checkout modify the HEAD.

Enter image description here

Community
  • 1
  • 1
CodeWizard
  • 128,036
  • 21
  • 144
  • 167
  • 5
    That just saved me many hours of work. I used "git reflog --date=iso" to see the date/time for each entry since I couldn't tell for sure without the timestamp. – MetalMikester Dec 10 '18 at 13:43
  • 1
    for me, in `git reset --hard `, removing `HEAD` worked! +1 for graphical representation!!. – reverie_ss Dec 11 '18 at 13:22
  • 1
    Just to mention: if you know the branch name: `git reflog ` can be quite useful, since you see the changes of just one branch. – Markus Schreiber Jun 09 '20 at 13:47
  • 3
    Nice explanation. I tend to use `git cherry-pick ` on the branch where I want it to come to put it there. – Emile Vrijdags Feb 12 '21 at 11:08
59

Another way to get to the deleted commit is with the git fsck command.

git fsck --lost-found

This will output something like at the last line:

dangling commit xyz

We can check that it is the same commit using reflog as suggested in other answers. Now we can do a git merge

git merge xyz

Note:
We cannot get the commit back with fsck if we have already run a git gc command which will remove the reference to the dangling commit.

Atri
  • 5,511
  • 5
  • 30
  • 40
  • 6
    This is the only answer that works if you haven't recently pointed at the commit in question, such as when you fetch a branch and then accidentally reset that branch elsewhere. – TamaMcGlinn Feb 19 '20 at 13:22
17

This happened to me just today, so I am writing what came out as a lifesaver for me. My answer is very similar to @Amber 's answer.

First, I did a git reflog and searched for that particular commit's hash, then just copied that hash and did a git cherry-pick <hash> from that branch. This brought all the change from that lost commit to my current branch, and restored my faith on GIT.

Have a nice day!

zean_7
  • 336
  • 3
  • 12
16

First of all use git reflog to list all your commits even the lost commit

git reflog

Then use git log HEAD@{your_commit_number} to find the commit you are looking for. e.g

git log HEAD@{17}

Checkout into the commit after you find it with git checkout HEAD@{your_commit_number} e.g

git checkout HEAD@{17}

You may need to add and commit your changes

git add .
git commit -m"quuck_fix"

Then, you will have to create a temporary branch to restore the commit back to your branch

git branch temp

Finally, you will checkout into your existing branch and then merge the temporary branch.

#git checkout <your_existing_branch> e.g

git checkout main
git merge temp
Micheal Shoyemi
  • 171
  • 1
  • 5
15

Try this, This will show all commits recorded in git for a period of time

git reflog

Find the commit you want with

git log HEAD@{3}

or

git log -p HEAD@{3}    

Then check it out if it's the right one:

git checkout HEAD@{3}

This will create a detached head for that commit. Add and commit any changes if needed

git status 
git add
git commit -m "temp_work" 

Now if want to restore commit back to a branch lets say master you will need to name this branch switch to master then merge to master.

git branch temp
git checkout master
git merge temp

Here's also a link specifically for reflog on a Git tutorial site: Atlassian Git Tutorial

Vic Seedoubleyew
  • 9,888
  • 6
  • 55
  • 76
Ventrova
  • 151
  • 1
  • 3
8

If you cannot find your commit with git reflog and it happen that you were using IntelliJ IDE you can right click on your project root folder -> Local History -> Show History and revert your changes from there.

I messed up doing git rebase with git push -f and this truly saved me since the commit was dropped from the local and remote repositories.

Hope that saves someone's day

Cheers

  • Hey So I have VS running and I have the commit id of a commit ec101349 how can i filter my reflog with this id? is it possible? – d0rf47 Oct 27 '22 at 15:48
1

The safest way is to

  1. Find commit head number for state you want to restore

git reflog or git reflog | grep your_phrase

  1. Create new branch off it

git checkout -b your-branch HEAD@{<your-number>}

pymen
  • 5,737
  • 44
  • 35
-21

Sadly git is so unrelable :( I just lost 2 days of work :(

It's best to manual backup anything before doing commit. I just did "git commit" and git just destroy all my changes without saying anything.

I learned my lesson - next time backup first and only then commit. Never trust git for anything.

Ziv Barber
  • 595
  • 9
  • 13
  • 2
    Could you please go through a basic git tutorial? :) e.g.: https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners I would not like to offend you but you don't get it right. You can trust git. You just have to learn to use it. :) – F. Norbert Sep 08 '20 at 13:24
  • I'm used git for years. It's a bug in git and not related to user land: I did git commit as normally but it destroyed all my stuff so I can't see all my changes. git log gives noting and git went back to the state before the changes. Git didn't even reported anything. I guess that git crashed somewhere in the middle of commit. – Ziv Barber Sep 08 '20 at 16:08
  • I never lose work unless `nano` crashes. You might have an issue we don't, or you may have fsck'ed up without knowing, i've done it many times ;D – TheTechRobo the Nerd Sep 09 '20 at 01:03
  • Also, if git crashes in the middle of the commit, it won't revert all your changes — worst case scenario it'll create a corrupt commit that you can revert. Sure you didn't `git stash;git stash drop`? – TheTechRobo the Nerd Sep 09 '20 at 01:04
  • 2
    git is the wold-wide industry standard versioning tool. It is used by everyone from mega-corporations to students. Do you really think everyone would be using a tool so buggy that it fails to do the only thing that its supposed to do? – Dino Prašo Mar 30 '21 at 11:06
  • It may not be git's fault. :-) However, the variety and complexity of the above solutions to this simple problem show that it is a good idea to back up your whole local repo before attempting anything tricky. It's a lot easier to restore a backup than to try to understand the problem and possible solutions. I wish I'd done that before I screwed up my rebase last night. :-) – Denis Howe Feb 21 '23 at 12:04