-1

I was working on a file, and then I added it to the index with git add file

I did not commit the file. I then ran git rm file. it deleted the file, and I cannot use git reset file because it was never committed. Similarly I cant unstage the deletion because it was never committed.

while there are similar questions on so, none are this particular edge case. none of the solutions suggested in those simiilar posts worked for me.

Please help! the file that was deleted is not even in my trash. Have I unfortunately found the one way to permanently delete a file in git with no hope for recovery?

thanks,

Paul

Paul
  • 1,106
  • 1
  • 16
  • 39
  • "Have I unfortunately found the one way to permanently delete a file in git with no hope for recovery?" No. You have found one way, but not _the_ one way. There are many others. But yes, `git rm file` is just like `rm file` — it simply erases the file. – matt Jul 20 '22 at 00:37
  • However, things are not as bad as they might have been. Under the right circumstances, a simple sequence of two Git commands can erase your whole hard disk (or most of it anyway). See for example https://stackoverflow.com/questions/72647089/git-init-reset-hard-deleted-all-my-desktop-files – matt Jul 20 '22 at 00:42
  • thank, I guess I thought git commands could do less damage in general than generic shell commands-- clearly I was wrong! – Paul Jul 25 '22 at 19:03
  • If you know about generic shell commands, `git rm` should scare you just as much as `rm`. Phrases like `--hard` and `--force` should also make you think long and hard before pressing the magic button. – matt Jul 25 '22 at 20:48
  • but to clarify, if the file is either 1) not tracked yet or 2) is tracked and committed, git rm will be less dangerous right? because in case 1 it will simply fail, and in case 2 it can be easily recovered with git reset. So it isn't really equally dangerous as rm except in this circumstance right? – Paul Jul 25 '22 at 21:07

1 Answers1

1

Run git fsck and look for dangling blob hash IDs (you can run git fsck --unreachable if you prefer but for this case it should produce the same useful information, and --unreachable disables --lost-found). Add --lost-found to make things much easier: for each of those "dangling blob" objects that git fsck reports, Git will write a file to .git/lost-found/other/ with a bizarre hash-ID name such as 04d0fd1fe60702c2040f3658301ce7e322761ceb.

Now that you have these files in .git/lost-found/other, examine each file. One of them will contain the data you removed. The file name is gone, but the contents can be recovered this way.

If the file contents exactly match some committed file, it won't turn up in the lost-and-found, but in this particular case, that seems improbable.

(When you're done, you can simply remove the .git/lost-found directory entirely. Be careful removing it of course!)

The hard way

If you use --unreachable, you'll need to git cat-file -p each hash ID, e.g.:

$ git fsck --unreachable
Checking object directories: 100% (256/256), done.
unreachable commit 06f1c305bbd945cb2b9533a4bb237b149cac26ce
unreachable blob 070d406b64141edb1f619acfc2e9d2f2d8a9fe6c
unreachable blob 20943aebb3b8f4b43e56009d4143744cf9d98239
unreachable blob 28b87432a538a032e3b6ac7cc3833023e6f505e5
unreachable tree 5645793dccf3ec49312efa72156b09effdec5e2a
...

Using git cat-file -p on each of those blob hash IDs, I see various bits of junk I git add-ed or that Git created during merge conflicts or whatever. In your case, you'd get the initial file contents from your git adds (plus, perhaps, some other junk: Git feels free to create trash objects, secure in the knowledge that after 14 or 30 or 90 days or so they'll be cleaned-up).

torek
  • 448,244
  • 59
  • 642
  • 775
  • thank you for your response. I thought there might be a backup like this. So git tracks these blobs even if they are never committed? I tried you suggestion, but after running `git fsck --unreachable --lost-found` I still do not see a folder in `.git/lost-found` – Paul Jul 25 '22 at 19:07
  • *Tracks* is the wrong word to use here (it implies too much), but `git add` compresses the data and makes a blob object out of it if it's not already in there. I always just use `git fsck --lost-found` (without `--unreachable`); it seems that `--unreachable` disables the `--lost-found` action. Let me update the answer to note this. – torek Jul 25 '22 at 20:39
  • that worked. It looks like these lost and found blobs will show up the same regardless of which branch you're on. and I assume they will never be deleted? I couldn't find my file unfortunately. I see a bunch of unresolved merges and things like that. I have already rewritten my file and moved on, but this is a good thing to know and hopefully it helps someone else in my position in the future. – Paul Jul 25 '22 at 21:00
  • "Lost and found" items aren't connected to *anything*. They will last at least 14 days from the time of creation (by default), and possibly longer, and then will be removed. However, once `git fsck --lost-found` has extracted the blob data to the lost-found directory, it should remain there until you do something with it. – torek Jul 25 '22 at 21:13
  • Note that in Git, branch names are irrelevant *except* that they start this whole "finding" process, by finding some commit: the *name* stores the *last* commit hash ID that is to be considered "part of the branch". The commit (found by hash ID) then "finds" all of its committed files, and also the hash ID(s) of its parent commit(s). Most commits have one parent, so that produces, by induction, a string of commits. The string of commits we find when we use a branch name, well, people call that "a branch". But they also call the name "a branch", and use the word "branch" for other things too. – torek Jul 25 '22 at 21:16