24

How to restore an accidentally deleted file and folder in git after push. Below is the scenario.

  1. Accidentally deleted a folder which has a single file and made a bunch of changes to other files.
  2. Now, pushed all these changes. So this push has the deleted folder along with other changed files.
  3. On top of this, there were a few more pushes.

Now, can I restore the deleted file, along with history and then push back to repo.

Venu
  • 1,513
  • 3
  • 19
  • 37
  • 1
    Git doesn't *have* "file history". Git has *commit history*. Restore the file(s) and your history says "commit K deleted some files, later commit R produced new files with the same name and the same contents as before." That's as close as you get. Use Ryan's answer below to get the file(s) back. – torek Feb 17 '17 at 01:21
  • If you didn't use git to remove them you could reset your workspace to get them back. Are you sure they are deleted? – osowskit Feb 17 '17 at 05:46
  • @osowskit what do you mean by "if you did not use git to remove" . My question itself is "how to restore if I deleted the file and pushed the deleted file?" – Venu Feb 20 '17 at 07:49
  • Thx. I'd recommend including the git commands you used to clarify that this wasn't deleting on the client-side only. I'd revert the commit to avoid rewriting history. – osowskit Feb 20 '17 at 16:02

4 Answers4

18

It is possible, with help of Git copy file preserving history you need to copy the file before it was deleted.

I will write here a complete example. First I will prepare some test repository:

git init
echo "test content" > file.txt
git add file.txt
git commit -m "start"
echo "test content 2" >> file.txt
git commit -am "next commit"
rm file.txt
git commit -am "Delete file, lose history"

Now we have a test repository without the file. To restore the file with its commit history the process is following: create a branch where the file did exist. Then make two copies of this file, each with history. Then merge back to master and only one of the two copies will get deleted during the merge. Be sure to use your commit hash instead of 190112b in example below.

git checkout 190112b -b before-deletion
git mv file.txt file1.txt
git commit -m "Move file (1)"
SAVED=`git rev-parse HEAD`
git reset --hard "HEAD^"
git mv file.txt file2.txt
git commit -m "Move file (2)"
git merge $SAVED
git commit -a -n

OK, so now in this branch we have two copies of this file. Each copy preserves history. Now when we merge this back into master, one file will disappear (or will have wrong history), the other one will keep the history.

git checkout master
git merge before-deletion
git commit -a -n
git rm file1.txt
git mv file2.txt file.txt
git commit -m "recovery finished"

And that's it.

Janek_Kozicki
  • 736
  • 7
  • 9
  • Worked. Restored the file with its history. Thanks! – Rodrigo Elias Aug 06 '20 at 17:03
  • @RodrigoElias great to hear! :) – Janek_Kozicki Aug 06 '20 at 20:24
  • I followed your steps above, but had errors with `git merge`. When I ignored the errors and carried on with the next command, it all just worked. Amazing! – Zack Xu Dec 03 '20 at 14:35
  • Was it line `git commit -m "next commit"` ? I will remove it, it's unnecessary, the next command fixes it. – Janek_Kozicki Dec 04 '20 at 15:20
  • It was in a few places:the second block `git merge $SAVED`. I got a `CONFLICT (rename/rename): Rename "file.txt"->"file2.txt" in branch "HEAD" rename "file.txt"->"file1.txt" in " ...`. I used git 2.7.4 – Richard Feb 05 '21 at 00:20
  • Worked as a charm. I just ignored the warning. hanks! – buzztr Oct 04 '22 at 05:16
  • Can you add comments before each git command? I don't know what is specific of this example and what should be changed. For example, what if the commit that deleted the file is not the one before HEAD? – Alechan Oct 25 '22 at 13:30
  • After trying many different methods. Finally this solution worked to restored directly with history intact. Thanks for sharing. – Ali Azhar May 08 '23 at 17:24
16

Sure, just check it out from a commit where it existed. If the commit that deleted the file is the tip of whatever you have currently checked out, that’s HEAD^ (the commit before last):

git checkout HEAD^ -- path/to/file

Then you can commit and push it.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • 3
    You can replace HEAD^ with a commit SHA and that will also work. – Peter Reid Feb 17 '17 at 09:41
  • 11
    I tried that but it does not restore the history for me. – waynix Oct 25 '18 at 06:47
  • @waynix: You need to pick a commit where the file exists. It’s not always going to be `HEAD^`. – Ry- Oct 25 '18 at 07:44
  • 4
    @Ry-: I did get the file back, but the history was lost. But when I execute git blame on the file I only get my name and not the name of the original committer. – waynix Nov 02 '18 at 11:15
  • @waynix: Oh, sorry, misread that. Is the history there if you use `git log` instead of `git blame` on the file? (Or did you checkout from a commit in a separate timeline of sorts?) – Ry- Nov 02 '18 at 13:13
  • What is the latest word on this? Was history maintained? Does `git log` show the history of the restored file before the deletion? – Garret Wilson Feb 24 '19 at 22:36
  • 4
    This did not preserve history for me; I see only the latest commit in the file's history. FWIW I checked out using the commit hash. – aggregate1166877 Apr 08 '20 at 22:16
  • 1
    This did not retain the history for me. – OSGI Java Aug 31 '21 at 17:15
  • @GarretWilson See MadHatter's response, which retains history and is short and elegant. – Janus Troelsen Aug 10 '23 at 19:43
6

Just encountered a similr scenario, paste the possible solution here.
A file gets deleted earlier, now I need to restore.
Two steps: 1. Locate the commit which deletes the file 2. Restore the file from that commit.

  1. git log --all --stat --diff-filter=D -- test.log(Say the file name is test.log)
  2. git restore --source aec723390^ test.log(Say the output of the step 1 is "aec723390", note the ^)
MadHatter
  • 301
  • 3
  • 12
-1

Assuming you're currently on the master branch, an easy solution is to find the GIT SHA1 from the last commit (using something like gitk helps) with the deleted file you want.

Run the command

git checkout <GIT SHA1 value>

Copy the contents of the file into notepad (or any text editor)

Run the command

git checkout master

Recreate the file with the contents from notepad

ted-k42
  • 356
  • 3
  • 12