I fixed this problem on my git repository, where I believe it was caused by a dodgy filesystem (on a Linux virtual machines hosted on Windows) acting up on a hard reset.
I started out in the same place as you, with:
jack@machine:~/git/cs$ git status
error: object file .git/objects/2e/f529faaaed03b2384b9f4d49a2ea95d7833894 is empty
error: object file .git/objects/2e/f529faaaed03b2384b9f4d49a2ea95d7833894 is empty
fatal: loose object 2ef529faaaed03b2384b9f4d49a2ea95d7833894 (stored in .git/objects/2e/f529faaaed03b2384b9f4d49a2ea95d7833894) is corrupt
Before doing anything, I backed up the whole tree by making a recursive copy of it into another folder. Do this.
Then I forcibly removed the object which was corrupt:
jack@machine:~/git/cs$ rm .git/objects/2e/f529faaaed03b2384b9f4d49a2ea95d7833894
rm: remove write-protected regular empty file ‘.git/objects/2e/f529faaaed03b2384b9f4d49a2ea95d7833894’? y
I then got a different problem which prevented me from running any git commands:
jack@machine:~/git/cs$ git status
fatal: bad object HEAD
Instead of doing a checkout
as some people recommend to get HEAD
back to a good state, I did reset
. checkout
changes both the state of your tree and the branch that you are on. reset
(without --hard
) changes the branch that you are on, but doesn't change any of the files. I wanted to keep all the files I had in their current state, all the more so since they are the only record of my recent commits (since the branch that I am on, has some problem, and can't be logged).
When I last could use git, I was on a feature branch, call it feature_foo
. I couldn't reset to feature_foo
since it pointed to the deleted commit 2ef529fa..
I reset to master
. I believe it doesn't matter where you reset to, any other branch should do.
jack@machine:~/git/cs$ git reset master
Unstaged changes after reset:
M a/bunch/of_changes
M more/changes
error: Trying to write ref ORIG_HEAD with nonexistent object 2ef529faaaed03b2384b9f4d49a2ea95d7833894
error: Cannot update the ref 'ORIG_HEAD'.
Now I am on master
, but with the same file tree that I had before. Since feature_foo
was quite different from master
, I see loads of unstaged, uncommitted changes. This is normal. I think the message about ORIG_HEAD
just means that git records my previous location somewhere, and right now it's not happy because my previous location is the deleted commit.
Now that I have a proper HEAD
, I can do git reflog
:
jack@machine:~/git/cs$ git reflog
61ac654 HEAD@{0}: commit: Commit message from a commit I did earlier
f9a1ce9 HEAD@{1}: commit: Another commit message
b26a6e9 HEAD@{2}: commit: Yet another commit message
Here I see that all the commits I did on the feature branch before losing my work are still there. I think that only the most recent one, 2ef529fa..
was lost of course. I would like to reset to HEAD@{1}
to be back on a branch with these commits.
jack@machine:~/git/cs$ git reset HEAD@{1}
fatal: Log .git/logs/HEAD is corrupt.
So I open this file to edit it:
jack@machine:~/git/cs$ vim .git/logs/HEAD
This file looks like a bunch of SHA1s and commit messages, until the last few lines:
b26a6e99762e703914dc3749fe136d99e100ac74 f9a1ce9c9eaa54b51aa29efdeafec023202de470 Jack <jack@example.com> 1434447540 +0100 commit: Another commit message
f9a1ce9c9eaa54b51aa29efdeafec023202de470 420ded21ffed88a2865cc0adaf3f54b0b44864e2 Jack <jack@example.com> 1434449503 +0100 commit: Commit message from a commit I did earlier
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@2ef529faaaed03b2384b9f4d49a2ea95d7833894 53b404d482a426046f2de6484b8855d1154b7fca Jack <jack@example.com> 1434465895 +0100 reset: moving to master
In other words, I see the same valid commits in the reflog, then a bunch of garbage, then a commit which shows me resetting to master
FROM the invalid commit (scroll right to see it).
I delete all the garbage and everything past it, then save the file. Now I can look at the reflog again:
jack@machine:~/git/cs$ git reflog
61ac654 HEAD@{0}: commit: Commit message from a commit I did earlier
f9a1ce9 HEAD@{1}: commit: Another commit message
b26a6e9 HEAD@{2}: commit: Yet another commit message
Now, the abbreviated SHA1 from the first line, 61ac654
, seems to point to master
. This is confirmed by me looking further down the reflog and seeing the same SHA1 appear in other places, when I was on master
. Furthermore, doing git reset HEAD@{0}
doesn't do anything at all. But if I do:
jack@machine:~/git/cs$ git reset HEAD@{1}
Unstaged changes after reset:
M just/a/few_changes
The small number of unstaged changes shows me that my file tree is now very close to what I have committed in Git. Doing git log
confirms that I have all the commits I saw in the reflog in my history now, except for the first one. So I just have to re-commit this commit, and the naughty one 2ef529f
to get exactly back to where I started!
This took some figuring out, but meant I didn't lose the dozen or so commits since my last push.