Venu
Venu

Reputation: 1782

Restore deleted file with history in git

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.

Upvotes: 30

Views: 23430

Answers (5)

VonC
VonC

Reputation: 1330012

My current one-liner, for a given deleted file I know the exact name and path, from a Windows CMD:

bash -c "git restore -SW -s $(git log -n 1 --diff-filter=D --pretty=%H -- :/path/to/file)^ -- :/path/to/file"

By using the pathspec :/path/to/file, I reference the deleted file with a relative path from the root of the working tree, even when I am running the command from inside a subdirectory.
See more at "How does git interpret a colon followed by a path?".

The git restore -SW part directly restores the file both in the working tree and the index, ready to be committed.

Upvotes: 1

MadHatter
MadHatter

Reputation: 395

Just encountered a similar scenario: A file was previously deleted, now I need to restore it.

Step 1: Locate the commit which deletes the file (say the file name is test.log):

$ git log --all --stat --diff-filter=D -- test.log
commit aec72339081df3bc621a6c0cd3687257778466e4
(Author, Date, commit message etc appear here)

Step 2: Restore the file from that commit (aec723390 from above), note the ^ for the prior commit containing the not-yet-deleted file:

$ git restore --source aec723390^ -- test.log

Step 3: The file will be restored to your working tree (but not the repo until you actually commit it), you may add it via git add test.log then make a commit:

$ git status
On branch main
Your branch is up-to-date with 'origin/main'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    test.log

nothing added to commit but untracked files present (use "git add" to track)
$ 

Upvotes: 11

Janek_Kozicki
Janek_Kozicki

Reputation: 826

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.

Upvotes: 25

ted-k42
ted-k42

Reputation: 446

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

Upvotes: 2

Ry-
Ry-

Reputation: 225281

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.

Upvotes: 14

Related Questions