ChatGPT解决这个技术问题 Extra ChatGPT

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

git

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.
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.
Which duplicates @FelipeAlvarez? Looking to the horizon but found not one.. Maybe once upon a time there was a duplicate.

J
John Clements

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


What if you don't know the exact path? All you know is the filename?
@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.
@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.
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
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.)
F
Fatih Acet

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

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.
To see the commit hashes along with the deletes, you can do git log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'
Step 2 returns nothing. Any ideas of why it may happen? My filename is correct.
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
@TylerJones you can feed anything to anything with linux using pipes - google linux pipes.. you'll like that.
C
Calaf

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

Preliminary: Avoid confusion by stepping to the git root

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

> cd <project-root>

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.

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. 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

This is a lot more clearer than the accepted answer
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
I'm with @pouyan021 on this one. This answer quickly allowed me to find the commit in which the file was removed.
A
Akshay Agarwal

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

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?
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.
@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.
@Amber and the commit that you want is likely the most recent one before it was deleted, hence this answer.
@AlexR: <SHA>~1 should work the same without the need to wrap it with quote marks.
P
Petur Subev

@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.*

@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?
This does not find the file if it's in the project root (tested in Cygwin).
J
Jason

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.


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

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)


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

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

This is the most efficient way I found to locate a commit which deleted a specific file. Thanks a lot.
s
srghma

Summary:

Step 1

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

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

A
Antonio Petricca

Here is my solution:

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

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.