Reputation: 120
I had a bunch of changes added to the staging index by git add *
, but not yet commited, I wanted to remove them, undo the add, so I did git rm -rf .
to my surprise it removed them from my hard drive, I want a way to get them back; however, I have made huge changes and I would like to get those changes back.
TLDR: I deleted my whole project by git rm -rf .
, I need some way to reset the deletion, so that I keep my uncommited changes and get my files back. please I am too scared that I might lose my whole project.
ANSWER: My repository is basically a website with a lot of content, Based on the answers below, I made 2 copies of my repository, let's call them copy A and copy B, for A I did git reset --hard
to go back to the latest commit, I got my files back, but lost the changes I made to them. so for copy B I did git fsck --lost-found
and went into the .git/lost-found/other/ directory which contained multiple hash-named versions of my files, I kept opening each of them, they were more than 60 files btw, each file I recognize I rename it to it's actual name and then place it instead of the older versions inside of copy A, at the end I deleted my original repo and I am using copy A now as my website. it is as thought nothing have happened now. One Little Stupid Mistake => 5 Hours of Pain. Don't repeat what I did, never ever.
right now git status
shows all my files as "deleted: " and its in green.
Upvotes: 2
Views: 1387
Reputation: 2883
git status
gives you some hints on what commands you could use to restore the files:
$ git rm -rf .
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: file1
deleted: file2
To unstage the deleted files:
$ git reset HEAD file1 file2
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: file1
deleted: file2
no changes added to commit (use "git add" and/or "git commit -a")
Checkout the deleted files:
$ git checkout -- file1 file2
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
Upvotes: 1
Reputation: 2095
The first thing you should do, as the commenters said, is backup your project directory.
You can get your committed files back with git reset --hard HEAD
. Since you cleared your staging tree your uncommitted changes aren't in git anymore (as several other answers point out, this may not be true) so your only chance of recovering them is any backups you or your OS might have made.
I'm sorry it doesn't help with the immediate situation but for future reference you can unstage your changes with git reset HEAD
.
Upvotes: 0
Reputation: 181745
There may be hope: the objects that you previously added to the index may still exist, although they are no longer referenced. I did the following to test:
$ git init test
$ cd test
$ echo hello > README.md
$ git add README.md
$ git commit -m"Add README.md"
$ echo world >> README.md
$ cat README.md
hello
world
$ git add README.md
$ git rm -f README.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: README.md
$ git fsck
Checking object directories: 100% (256/256), done.
unreachable blob 94954abda49de8615a048f8d2e64b5de848e27a1
$ git show 94954abda49de8615a048f8d2e64b5de848e27a1
hello
world
So even after git rm -f
, the file's contents as added to the index still exist. You can dump them all into .git/lost-found/other
by running git fsck --lost-found
.
The index itself isn't stored as a Git object, but resides directly in .git/index
, so I think this has been irreversibly overwritten. That means the paths to the files, as well as any metadata such as permissions, have been lost.
Upvotes: 3
Reputation: 1247
Using
find .git/objects/ -type f -printf "%T+\t%p\n" \
| sort \
| sed 's:.*git/objects/\(.*\)/\(.*\):\1\2:' \
| while read object; do
echo -n "$object ";
git cat-file -t "$object";
done
You should get a list of objects and type, ordered by time.
For example, on a test repo:
908553f63e9126f933b690970d41adc3377e3360 blob
31e0d0e213c9976308fbb91c542ced9218fa8f6a tree
5b181f91c49d287b4670fcf3545656dc0c0ef5f4 commit
de683137e0b2d0a40f766307e81999986e4b31c2 blob
086cb344a4fd8a9d671006b8e5844f2437faa3ab tree
930ba9809b5d50410b72c3fbff111d948f1027fa commit
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 blob
40cda8e010466dc7a4a0eb107e7e45804290685e blob
The last two blobs were created after the last commit, and if you print them with eg. git cat-file -p 40cda8e010466dc7a4a0eb107e7e45804290685e
, you should be able to recover the file contents.
You may also get some trees that way (use git ls-tree <tree-id>
to print them), but not the top-level one, since it was stored directly in the index.
Upvotes: 4
Reputation: 30868
For the files that have been committed, git reset --hard
would recover them all.
For those added but not committed, try git fsck --lost-found
. It will print dangling blobs and make their copies in .git/lost-found/other
. You can either run git cat-file -p $blob
or cat .git/lost-found/other/$blob
to see the content. The blobs do not record the file paths, so you need to map the content and the file path by memory, or by a keyword which is not newly modified with git grep $keyword
. After you find out a path for a blob, run cp .git/lost-found/other/$blob $path
to recover it.
Upvotes: 3