1834

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?

Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
Pedro Rolo
  • 28,273
  • 12
  • 60
  • 94
  • 24
    The answers here are more useful to me than the answers in the _duplicates_. – Felipe Alvarez Jun 07 '17 at 02:18
  • 17
    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. – Tim Boland Sep 15 '18 at 23:13
  • Which duplicates @FelipeAlvarez? Looking to the horizon but found not one.. Maybe once upon a time there was a duplicate. – Timo Mar 03 '22 at 21:23

11 Answers11

2254

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

John Clements
  • 16,895
  • 3
  • 37
  • 52
Amber
  • 507,862
  • 82
  • 626
  • 550
  • 2
    Try using a relative path instead of an absolute one (if you aren't already). – Amber Aug 26 '11 at 11:45
  • 73
    What if you don't know the exact path? All you know is the filename? – priestc Nov 16 '12 at 04:09
  • 2
    @priestc Answered in [another question](http://stackoverflow.com/questions/3845234/viewing-git-history-of-moved-files) – BryanH Jan 04 '13 at 15:25
  • 2
    @priestc: http://stackoverflow.com/questions/6017987/is-there-a-way-in-git-to-list-all-deleted-files-in-the-repository – Ciro Santilli OurBigBook.com May 03 '13 at 09:43
  • 2
    side note : your path must use '/' and not '\' took me a whole day to figure it out :/ – sliders_alpha Jun 20 '13 at 13:12
  • 22
    @PedroMorteRolo `git log -- ` will have no output when you are on a branch in which the file never existed. You should always use `git log --all -- `, to make sure you don't miss changes that happened on other branches. The command `git log -- ` 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. – hobs Feb 10 '14 at 18:29
  • 4
    @Amber, consider adding `--all` (thanks [Philip](http://stackoverflow.com/a/7204977/623735)) 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. – hobs Feb 10 '14 at 18:33
  • 3
    As stated in the answer below, restoring the file should be `git checkout ^ -- ` (note the ^ symbol), because at the moment of commit the file is deleted, we need to look at the previous commit to get the deleted file's contents – kipelovets Feb 18 '15 at 12:56
  • @kipelovets that assumes you're using the sha of the delete commit, rather than the sha of the version of the file you wanted. – Amber Apr 02 '16 at 06:18
  • @kipelovets I don't see why `^` would be necessary. Why would you choose the hash after the last one that has the file? – Geremia May 25 '16 at 21:20
  • 5
    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.) – torek Dec 06 '16 at 17:40
  • This did not work for me, the command returns nothing, but [second most voted answer](http://stackoverflow.com/a/21871377/284111) worked. – Andrew Savinykh Jan 09 '17 at 05:54
  • I ran the command `git log --all -- ` which does give me some history of the file: when the file is added and changed. But it doesn't show the commit when the file is moved or deleted. any cases which are not covered in the discussion above? – sgu Feb 11 '17 at 01:14
  • 2
    Make sure your change directory to the root of the git projects. I had problems with the relative path when using the commands from a sub directory – jorgenfb Mar 27 '17 at 08:27
  • filename is case sensitive. Good to know for windows users where cmds usually aren't. – jgauffin May 17 '17 at 15:24
  • Doesn't work in git 2.7.4 + fish shell. The alternative answer by Calaf if you have this combination. – Adnan Y May 17 '17 at 18:16
  • When I run the first cmd it list commits that has nothing to do with the deleted file – Elia Weiss Aug 02 '18 at 06:05
  • 1
    add `--stat` to your `git log` command to actually see the files modded in the returned commits. – Stuart Mclean May 17 '19 at 08:56
  • `git log --all -- ` is enough for my case to find deleted file – vuhung3990 Jul 01 '19 at 07:39
  • @jonS90 I'm not sure what shell you use, but neither bash nor zsh will expand wildcards inside double quotes. – Amber Nov 13 '20 at 08:48
  • @Amber you're right. Whatever I thought I saw I can't reproduce. I'm going to delete that comment. – jonS90 Nov 27 '20 at 02:51
  • Why is the caret not needed for `show`? I want to be 'show'n the file before the delete. – Timo Dec 29 '22 at 19:28
  • Curious, why `git log ^ -- ` return error. But if I do `git checkout ^` as first step then `git log ^ -- ` works. That is a bit strange. – Eugen Konkov Apr 06 '23 at 00:42
  • Tip: Depending on your use case, you might find it helpful to include `--no-merges` to exclude merge commits. – Sam Aug 09 '23 at 16:29
500

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
Fatih Acet
  • 28,690
  • 9
  • 51
  • 58
  • 2
    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`. – JacobF Jun 06 '14 at 13:39
  • 7
    To see the commit hashes along with the deletes, you can do `git log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'` – Chris Middleton Mar 20 '15 at 21:38
  • 2
    Step 2 returns nothing. Any ideas of why it may happen? My filename is correct. – Denys Kniazhev-Support Ukraine Jul 24 '15 at 11:07
  • 2
    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` – randomor Dec 16 '15 at 03:58
  • `git log --name-only --diff-filter=D --pretty=format: | awk 'NF'` is IMO a cleaner alternative of the first command (to print all now deleted files ever in the repo) – user7610 Jan 19 '16 at 18:53
  • Or to directly get commit hashes with all files they delete: `git log --name-only --diff-filter=D --format="%H%b"` – Maarten Nov 29 '17 at 15:02
  • 1
    @TylerJones you can feed anything to anything with linux using pipes - google `linux pipes`.. you'll like that. – John Hunt Oct 04 '18 at 12:49
106

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
Calaf
  • 10,113
  • 15
  • 57
  • 120
  • 11
    This is a lot more clearer than the accepted answer – pouyan021 May 25 '19 at 07:32
  • 2
    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` – user5542121 Jan 10 '20 at 11:06
  • 1
    I'm with @pouyan021 on this one. This answer quickly allowed me to find the commit in which the file was removed. – Yinci May 31 '22 at 07:34
  • 1
    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"` – Silverfish Nov 06 '22 at 16:48
41

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
Akshay Agarwal
  • 1,959
  • 1
  • 16
  • 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? – Tony K. Sep 04 '13 at 16:30
  • 21
    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 Sep 11 '13 at 14:07
  • 6
    @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 Nov 25 '13 at 21:33
  • 7
    @Amber and the commit that you want is likely the most recent one before it was deleted, hence this answer. – Sam Holder Jan 16 '15 at 20:39
  • Thanks for the ^ tip ^. Beware in windows it needs to be double-quoted. – Alex R Sep 27 '15 at 00:11
  • 1
    @AlexR: `~1` should work the same without the need to wrap it with quote marks. – CodeManX Jun 15 '16 at 11:18
37

@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.*
Petur Subev
  • 19,983
  • 3
  • 52
  • 68
  • 7
    @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? – Clément May 28 '16 at 15:18
  • 3
    This does not find the file if it's in the project root (tested in Cygwin). – wortwart Nov 22 '17 at 09:25
25

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.

Jason
  • 2,246
  • 6
  • 34
  • 53
  • 1
    Awesome, thanks! Looks like my file never existed at all, but that's a separate and much hairier issue… –  Feb 27 '15 at 16:28
  • make sure you run this from the repository root directory if your file seems to be 'missing' – samaspin Jul 18 '19 at 11:00
19

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)

Philip Oakley
  • 13,333
  • 9
  • 48
  • 71
13

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
floer32
  • 2,190
  • 4
  • 29
  • 50
jasonleonhard
  • 12,047
  • 89
  • 66
7

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
srghma
  • 4,770
  • 2
  • 38
  • 54
2

Here is my solution:

git log --all --full-history --oneline -- <RELATIVE_FILE_PATH>
git checkout <COMMIT_SHA>^ -- <RELATIVE_FILE_PATH>
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
  • 1
    Please read [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. – Adriaan Jun 10 '22 at 07:41
0

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>
TTT
  • 22,611
  • 8
  • 63
  • 69