Advertisement
Advertisement


Find and restore a deleted file in a Git repository


Question

Say I'm in a Git repository. I delete a file and commit that change. I continue working and make some more commits. Then, I find I need to restore that file.

I know I can checkout a file using git checkout HEAD^ foo.bar, but I don't really know when that file was deleted.

  1. What would be the quickest way to find the commit that deleted a given filename?
  2. What would be the easiest way to get that file back into my working copy?

I'm hoping I don't have to manually browse my logs, checkout the entire project for a given SHA and then manually copy that file into my original project checkout.

2016/02/24
1
2864
2/24/2016 11:31:30 AM

Accepted Answer

Find the last commit that affected the given path. As the file isn't in the HEAD commit, this commit must have deleted it.

git rev-list -n 1 HEAD -- <file_path>

Then checkout the version at the commit before, using the caret (^) symbol:

git checkout <deleting_commit>^ -- <file_path>

Or in one command, if $file is the file in question.

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

If you are using zsh and have the EXTENDED_GLOB option enabled, the caret symbol won't work. You can use ~1 instead.

git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"
2018/04/03
3200
4/3/2018 5:11:57 PM

  1. Use git log --diff-filter=D --summary to get all the commits which have deleted files and the files deleted;
  2. Use git checkout $commit~1 path/to/file.ext to restore the deleted file.

Where $commit is the value of the commit you've found at step 1, e.g. e4cf499627

2019/01/18

To restore all those deleted files in a folder, enter the following command.

git ls-files -d | xargs git checkout --
2020/05/13

I came to this question looking to restore a file I just deleted but I hadn't yet committed the change. Just in case you find yourself in this situation, all you need to do is the following:

git checkout HEAD -- path/to/file.ext

2014/04/10

If you’re insane, use git-bisect. Here's what to do:

git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>

Now it's time to run the automated test. The shell command '[ -e foo.bar ]' will return 0 if foo.bar exists, and 1 otherwise. The "run" command of git-bisect will use binary search to automatically find the first commit where the test fails. It starts halfway through the range given (from good to bad) and cuts it in half based on the result of the specified test.

git bisect run '[ -e foo.bar ]'

Now you're at the commit which deleted it. From here, you can jump back to the future and use git-revert to undo the change,

git bisect reset
git revert <the offending commit>

or you could go back one commit and manually inspect the damage:

git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .
2011/03/28

My new favorite alias, based on bonyiii's answer (upvoted), and my own answer about "Pass an argument to a Git alias command":

git config alias.restore '!f() { git checkout $(git rev-list -n 1 HEAD -- $1)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- $1)~1 | grep '^D' | cut -f 2); }; f'

I have lost a file, deleted by mistake a few commits ago?
Quick:

git restore my_deleted_file

Crisis averted.

Warning, with Git 2.23 (Q3 2019) comes the experimental command named git restore(!).
So rename this alias (as shown below).


Robert Dailey proposes in the comments the following alias:

restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"

And jegan adds in the comments:

For setting the alias from the command line, I used this command:

git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" 
2019/12/02

Source: https://stackoverflow.com/questions/953481
Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Email: [email protected]