In Git, how can I recover a staged file that was reverted prior to committing?
To expand on Alexander's answer with a simpler alternative: yes, if you've staged your changes then you can probably get your files back. When you run git add
, files are actually added to Git's object database. At the moment that you do, git will put the file in the index:
% git add bar.txt
% git ls-files --stage
100644 ce013625030ba8dba906f756967f9e9ca394464a 0 bar.txt
100644 6af0abcdfc7822d5f87315af1bb3367484ee3c0c 0 foo.txt
Note that the entry for bar.txt contains the object ID of the file. Git has actually added the file to its object database. In this case, Git has added it to the repository as a loose object:
% ls -Flas .git/objects/ce/013625030ba8dba906f756967f9e9ca394464a
4 -r--r--r-- 1 ethomson staff 21 14 Jun 23:58 .git/objects/ce/013625030ba8dba906f756967f9e9ca394464a
These files will eventually be garbage collected (so indeed, do not explicitly run git gc
). Thankfully, by default, this will happen in a matter of months, not days. Until these files are garbage collected, you can recover them.
The easiest way to do this is to download and install the git-recover
program in interactive mode:
% git recover -i
Recoverable orphaned git blobs:
61c2562a7b851b69596f0bcad1d8f54c400be977 (Thu 15 Jun 2017 12:20:22 CEST)
> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
> tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
> veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
> commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
Recover this file? [y,n,v,f,q,?]:
git-recover
looks for files in the object database that are not committed (or in the index). You can find out more about git-recover
in the blog post announcing it.
A very late answer that could simplify (a lot? comparing to other answers) the recover using the command line by letting you figure it out quicker which blobs should be recovered:
git fsck --full --no-reflogs --unreachable --lost-found | grep blob | cut -d\ -f3 | while read in; do printf "blob: $in\n"; git cat-file -p $in; printf "\n--------------------------------\n"; done > recover.txt
This command will create a file containing the hash and content of all the blobs that could be recovered.
That way, you could easily search into this file and recover the blobs you want with the given hash (with the command git cat-file -p 8f72c7d79f964b8279da93ca8c05bd685e892756 > myFile.txt
)
Disclaimer: this file could become huge and slow to create if you've got a lot of unreachable blobs.
If you prefer using GUI tools and are on Windows, you could also use GitExtensions that could be helpful to recover files.
If you had anything staged to git, you probably should be able to get that back. (If you just changed working copy, you wouldn't be able to restore it.)
First of all: do not run git gc
. Backup your repository and working copy before going ahead. (Make sure to backup .git
directory.) Also avoid closing terminal where this happened, and/or rebooting — if all fails, you have a chance to find stuff in history / memory.
Anyway, first thing to try is:
git fsck --lost-found
It will print something like
Checking object directories: 100% (256/256), done. Checking objects: 100% (30165/30165), done. dangling blob 8f72c7d79f964b8279da93ca8c05bd685e892756 dangling commit 4993502a6394491190d3f4d6fb3d1e14019c2e9b
Since you lost staged files and did not do a commit, you're interested in dangling blob
entries.
Run git show <sha>
for each one — some of them should be your files.