Recovering added/staged file after doing git reset --hard HEAD^?
You can (with some work) recover state of file at the last "git add <file>". You can use
$ git fsck --cache --no-reflogs --lost-found --dangling HEAD
and then examine files in '.git/lost-found/other' directory.
Please read git fsck manpage.
(I'm assuming that the missing file is not part of any commit. Otherwise, git log --all -g --diff-filter=D --stat
is your friend.)
-
Get list of unreachable files that
git
knows a file name:git fsck --unreachable --no-reflogs --no-cache HEAD | fgrep " tree " \ | cut -d " " -f3 | xargs -r -n1 git ls-tree \ | fgrep " blob " | cut -d " " -f 3- | sort -k2 -u
If you see something interesting,
git cat-file blob SHA-1-of-interesting-file
will output the file to standard output. (Example:git cat-file blob b8f0bdf56 > recovered-logo.png
)
Unfortunately, if the missing file is not part of the any commit, git does not have a timestamp and as such, you cannot print various versions of files ordered by time.
If the missing file has never been staged (git stage
or git add
) or stashed (git stash
), you're pretty much out of luck because as far as git knows, the file never did exist. (You may still try doing a git fsck --no-reflogs --lost-found
and looking around in directory .git/lost-found/other
to see if you have anything worth keeping in case git indeed has a copy of your missing file by some lucky accident. You do not have file names to help you in this case, only file contents.)
In case you just lost some commits (instead of just files), you'll probably want to run something like this:
gitk --all $( git fsck | awk '/dangling commit/ {print $3}'; git log -g --pretty='format:%H' )
That will run gitk
with all the branches, all the reflog and all the dangling commits. You may want to add -n 10000
or some other limit in case your repo has really many commits (say linux kernel). If you do not have gitk
, you may instead run lesser version using only command line like this:
git log --all --decorate --stat --graph --date-order $( git fsck | awk '/dangling commit/ {print $3}'; git log -g --pretty='format:%H' )
or a version with less verbose output
git log --all --decorate --oneline --graph --date-order $( git fsck | awk '/dangling commit/ {print $3}'; git log -g --pretty='format:%H' )
If you see some commit you want to save as branch recovered1
, simply do git checkout -b recovered1 <sha1-of-the-commit>
.