How to find a deleted file in the project commit history?

Asked 2023-09-21 08:10:14 View 466,988

Once upon a time, there was a file in my project that I would now like to be able to get.

The problem is: I have no idea of when have I deleted it and on which path it was.

How can I locate the commits of this file when it existed?

  • The answers here are more useful to me than the answers in the duplicates. - anyone
  • agreed...regardless of the duplicates...they didn't come up in the Google search....this one did...i hope we will stop wasting time chasing after duplicates...only time and google's algorithm will tell which question is the best. - anyone
  • Which duplicates @FelipeAlvarez? Looking to the horizon but found not one.. Maybe once upon a time there was a duplicate. - anyone

Answers

If you do not know the exact path you may use

git log --all --full-history -- "**/thefile.*"

If you know the path the file was at, you can do this:

git log --all --full-history -- <path-to-file>

This should show a list of commits in all branches which touched that file. Then, you can find the version of the file you want, and display it with...

git show <SHA> -- <path-to-file>

Or restore it into your working copy with:

git checkout <SHA>^ -- <path-to-file>

Note the caret symbol (^), which gets the checkout prior to the one identified, because at the moment of <SHA> commit the file is deleted, we need to look at the previous commit to get the deleted file's contents

Answered   2023-09-21 08:10:14

  • What if you don't know the exact path? All you know is the filename? - anyone
  • @PedroMorteRolo git log -- <path> will have no output when you are on a branch in which the file never existed. You should always use git log --all -- <path>, to make sure you don't miss changes that happened on other branches. The command git log -- <path> can be very dangerous if you have more than one branch and tend to forget paths and branches (like me) and it's also dangerous if you work with other developers. - anyone
  • @Amber, consider adding --all (thanks Philip) to your git log answer, so that people don't miss changes and files on other branches. It would save forgetful people like me a lot of grief. - anyone
  • As stated in the answer below, restoring the file should be git checkout <SHA>^ -- <path-to-file> (note the ^ symbol), because at the moment of <SHA> commit the file is deleted, we need to look at the previous commit to get the deleted file's contents - anyone
  • When using **/thefile.* it's usually a good idea to quote it, e.g., '**/thefile.*', to protect the glob * from the shell. (I'm not familiar with WIndows shells and when they eat *s, but if there's an accidental match from the current working directory in bash, that could make trouble.) - anyone

Get a list of the deleted files and copy the full path of the deleted file

git log --diff-filter=D --summary | grep delete

Execute the next command to find commit id of that commit and copy the commit id

git log --all -- FILEPATH

Show diff of deleted file

git show COMMIT_ID -- FILE_PATH

Remember, you can write output to a file using > like

git show COMMIT_ID -- FILE_PATH > deleted.diff

Answered   2023-09-21 08:10:14

  • Although I found the path with help of the first step, the second step throws this error: unknown revision or path not in the working tree. - anyone
  • To see the commit hashes along with the deletes, you can do git log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+' - anyone
  • Step 2 returns nothing. Any ideas of why it may happen? My filename is correct. - anyone
  • To find combine the three into one function, add this into your .bashrc or .zshrc: git-grep-latest(){ result_path=$(git log --diff-filter=D --summary | grep $1 | head -1 | awk '{print $4;}'); latest_commit=$(git log --all -- $result_path | head -1 | awk '{print $2;}'); git show $latest_commit -- $result_path; } and now you can just do: git-grep-latest some_text - anyone
  • @TylerJones you can feed anything to anything with linux using pipes - google linux pipes.. you'll like that. - anyone

Suppose you want to recover a file called MyFile, but are uncertain of its path (or its extension, for that matter):

0. (Preliminary) Avoid confusion by stepping to the git root

A nontrivial project may have multiple directories with similar or identical filenames.

> cd <project-root>
1. Find the full path
> git log --diff-filter=D --summary | grep delete | grep MyFile

`delete mode 100644 full/path/to/MyFile.js`

full/path/to/MyFile.js is the path & file you're seeking.

2. Determine all the commits that affected that file
> git log --oneline --follow -- full/path/to/MyFile.js

`bd8374c Some helpful commit message`

`ba8d20e Another prior commit message affecting that file`

`cfea812 The first message for a commit in which that file appeared.`
3. Checkout the file

If you choose the first-listed commit (the last chronologically, here bd8374c), the file will not be found, since it was deleted in that commit.

> git checkout bd8374c -- full/path/to/MyFile.js

`error: pathspec 'full/path/to/MyFile.js' did not match any file(s) known to git.`

Just select the preceding (append a caret) commit:

> git checkout bd8374c^ -- full/path/to/MyFile.js

Answered   2023-09-21 08:10:14

  • This is a lot more clearer than the accepted answer - anyone
  • for windows console (cmd), use find instead of grep in step 2: git log --diff-filter=D --summary | find "delete" | find "MyFile" And step3, note the quotes around the hash: git checkout "bd8374c^" -- full/path/to/MyFile.js - anyone
  • I'm with @pouyan021 on this one. This answer quickly allowed me to find the commit in which the file was removed. - anyone
  • Further to @user5542121's suggestion for Windows users, if you're using PowerShell instead of cmd then replace find by Select-String. So git log --diff-filter=D --summary | Select-String "delete" | Select-String "MyFile" - anyone

Could not edit the accepted response so adding it as an answer here,

to restore the file in git, use the following (note the '^' sign just after the SHA)

git checkout <SHA>^ -- /path/to/file

Answered   2023-09-21 08:10:14

  • I don't understand why you'd want the ^. The file is IN the commit with that SHA...why would you want to walk back another commit from there? - anyone
  • It's in the commit with that sha as "deleted" which means it still won't exist. You have to go to the commit before that to actually get it back. - anyone
  • @tandrewnichols which just means that you're using the wrong commit SHA - you want the commit for the version of the file you want... which probably isn't the version where the file is deleted. - anyone
  • @Amber and the commit that you want is likely the most recent one before it was deleted, hence this answer. - anyone
  • @AlexR: <SHA>~1 should work the same without the need to wrap it with quote marks. - anyone

@Amber gave correct answer! Just one more addition, if you do not know the exact path of the file you can use wildcards! This worked for me.

git log --all -- **/thefile.*

Answered   2023-09-21 08:10:14

  • @PedroMorteRolo Hmm. I don't know how I feel about copying an existing answer into the top-voted one :/ This answer was useful too on its own; an upvote might have been enough? - anyone
  • This does not find the file if it's in the project root (tested in Cygwin). - anyone

Below is a simple command, where a dev or a git user can pass a deleted file name from the repository root directory and get the history:

git log --diff-filter=D --summary | grep filename | awk '{print $4; exit}' | xargs git log --all -- 

If anybody, can improve the command, please do.

Answered   2023-09-21 08:10:14

  • Awesome, thanks! Looks like my file never existed at all, but that's a separate and much hairier issue… - anyone
  • make sure you run this from the repository root directory if your file seems to be 'missing' - anyone

Try using one of the viewers, such as gitk so that you can browse around the history to find that half remembered file. (use gitk --all if needed for all branches)

Answered   2023-09-21 08:10:14

  • That --all option is critical for both your answer and the accepted answer. - anyone
  • Browsing around history will take an extraordinary amount of time for most projects. - anyone

If you prefer to see the size of all deleted file

as well as the associated SHA

git log --all --stat --diff-filter=D --oneline

add a -p|--patch to see the contents too

git log --all --stat --diff-filter=D -p

To narrow down to any file you have two easy options, you can use a pathspec or you can pipe to grep and search for file name.

Using grep:

git log --all --stat --diff-filter=D --oneline | grep foo

Using a pathspec:

git log --all --stat --diff-filter=D --oneline -- '*foo*'

A pathspec can work well together with -p|--patch, if you want to see contents:

git log --all --stat --diff-filter=D --oneline --patch -- '*foo*'

You might also like this one if you know where the file is

git log --all --full-history -- someFileName

Answered   2023-09-21 08:10:14

  • This is the most efficient way I found to locate a commit which deleted a specific file. Thanks a lot. - anyone

Summary:

  1. Step 1

You search your file full path in history of deleted files git log --diff-filter=D --summary | grep filename

  1. Step 2

You restore your file from commit before it was deleted

restore () {
  filepath="$@"
  last_commit=$(git log --all --full-history -- $filepath | grep commit | head -1 | awk '{print $2; exit}')
  echo "Restoring file from commit before $last_commit"
  git checkout $last_commit^ -- $filepath
}

restore my/file_path

Answered   2023-09-21 08:10:14

Here is my solution:

git log --all --full-history --oneline -- <RELATIVE_FILE_PATH>
git checkout <COMMIT_SHA>^ -- <RELATIVE_FILE_PATH>

Answered   2023-09-21 08:10:14

  • Please read How to Answer and edit your question to contain an explanation as to why this code would actually solve the problem at hand. Always remember that you're not only solving the problem, but are also educating the OP and any future readers of this post. - anyone

I had this happen where I didn't even know what the file's name was, so I wanted to see all deleted files...

In general, I highly recommend becoming familiar with git-filter-repo. It has many uses for re-writing history, but one of its analysis features includes very quickly identifying all deleted files in a repo, and displaying their sizes and date deleted. (Using it on non-Windows OSes is fairly straight-forward, and here are installation instructions specifically for Windows.)

Once you have it runnable in your path, you simply run:

git filter-repo --analyze

This will output some files in your .git folder, and the one you want to look at for this question is called:

.git\filter-repo\analysis\path-deleted-sizes.txt

This file shows all deleted files in your repo, reverse sorted by size, and the date it was deleted. Here's an example output:

=== Deleted paths by reverse accumulated size ===
Format: unpacked size, packed size, date deleted, path name(s)
    57151421   44898377 2022-07-22 somdirectory/somefileA
    46034619   42929136 2022-01-18 somdirectory/somefileB
    65332368   29102439 2020-09-28 somdirectory/somefileC
    23686432   21681498 2022-07-22 somdirectory/somefileD
    23681272   21678818 2022-07-22 somdirectory/somefileE
    23676153   21670502 2022-07-22 somdirectory/somefileF
    43232768   21439037 2020-07-10 somdirectory/somefileG
    18714315   14299243 2019-01-10 somdirectory/somefileH
    16788104   13035176 2019-01-10 somdirectory/somefileI

Obviously you can use this to find the file you're looking for, or, in the context of re-writing history, based on the 2nd column sizes, I know if I remove those 9 deleted files from the history I'll reclaim about 220 MB.

Once you've identified the file you're looking for you can use this to find the commits:

git log --all --full-history -- <filename>

Answered   2023-09-21 08:10:14