1526

I have a Git repository with n commits.

I have a file that I need, and that used to be in the repository, and that I suddenly look for and think "Oh! Where'd that file go?"

Is there a (series of) Git command(s) that will tell me that "file really_needed.txt was deleted at commit n-13"?

In other words, without looking at every individual commit, and knowing that my Git repo has every change of every file, can I quickly find the last commit that HAS that file, so I can get it back?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
JohnMetta
  • 18,782
  • 5
  • 31
  • 57
  • 6
    Possible duplicate of [How to locate a deleted file in the commit history?](http://stackoverflow.com/questions/7203515/how-to-locate-a-deleted-file-in-the-commit-history) – Pedro Rolo Jan 12 '16 at 19:20
  • 2
    The link shared by Pedro had the answer to my question: how to find a deleted file when you don't remember the path. – Gordon Bean Apr 18 '17 at 15:17

9 Answers9

1673

To show the commits that changed a file, even if the file was deleted, run this command:

git log --full-history -- [file path]

If you want to see only the last commit, which deleted the file, use -1 in addition to the command above:

git log --full-history -1 -- [file path]

See also my article: Which commit deleted a file.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
vogella
  • 24,574
  • 4
  • 29
  • 26
  • 33
    is it possible to search for patterns? I forgot the whole name of the file =( maybe it is possible to get a log of all deletions? – wutzebaer Jun 27 '14 at 08:15
  • 12
    found it here: http://stackoverflow.com/questions/6017987/is-there-a-way-in-git-to-list-all-deleted-files-in-the-repository – wutzebaer Jun 27 '14 at 08:21
  • 13
    Please note, if you're using PowerShell, the hyphens have to be escaped: git log '--' [file path]. Hopefully this can same someone else some teeth-gnashing. – A. Wilson Aug 22 '14 at 20:24
  • 90
    I was able to search using `git log -- */<>.<>` not knowing the entire file path. – Tom Howard Sep 08 '15 at 16:38
  • Apparently, searching without square brackets yields results when adding square brackets does not. – MERose Apr 16 '16 at 22:17
  • 4
    @MERose square brackets are there as a placeholder for the real file path. – Emile Bergeron May 30 '16 at 17:37
  • 4
    If this command gives you nothing, verify that you are in the root folder of the git repository. – victorm1710 Sep 06 '19 at 09:05
  • What about if file was added using git lfs? – mrgloom Sep 17 '19 at 15:11
  • 4
    If this gives you a merge commit, add `--no-merges`. In either cay, you might also want to add `-p` to see the contents of the commit. – Robin Green May 23 '20 at 09:15
  • 1
    What if the file was deleted and I'm trying to find the commit that deleted it? – Boris Verkhovskiy Oct 01 '20 at 02:59
  • 1
    Doesn't work for me. Currently (after some difficult operations) git says that certain file, let's call it `foo/bar.php` is untracked (it shows as new untracked file in `git status`), but I KNOW FOR A FACT that this is an old and vital file and there is no reason for it to be deleted. The command you gave shows me TWO commits for this file, one that added it, and one that modified it. It DOESN'T show the commit that deleted it - and there MUST be a commit that deleted it, otherwise it wouldn't be untracked! – Szczepan Hołyszewski Aug 04 '21 at 13:06
  • @SzczepanHołyszewski I've seen stuff like that happen when code gets accidentally removed as part of resolving merge conflicts. It can make it very difficult to track down where it went! – starwed Aug 16 '21 at 20:42
  • But it also does show when this file was added. At least I see this behaviour at Windows CLI – Rax Wunter Mar 13 '23 at 11:40
  • git log --follow -- [file path] will works – Nisharg Shah May 18 '23 at 08:44
269

Short answer:

git log --full-history -- your_file

will show you all commits in your repo's history, including merge commits, that touched your_file. The last (top) one is the one that deleted the file.

Some explanation:

The --full-history flag here is important. Without it, Git performs "history simplification" when you ask it for the log of a file. The docs are light on details about exactly how this works and I lack the grit and courage required to try to figure it out from the source code, but the git-log docs have this much to say:

Default mode

Simplifies the history to the simplest history explaining the final state of the tree. Simplest because it prunes some side branches if the end result is the same (i.e. merging branches with the same content)

This is obviously concerning when the file whose history we want is deleted, since the simplest history explaining the final state of a deleted file is no history. Is there a risk that git log without --full-history will simply claim that the file was never created? Unfortunately, yes. Here's a demonstration:

mark@lunchbox:~/example$ git init
Initialised empty Git repository in /home/mark/example/.git/
mark@lunchbox:~/example$ touch foo && git add foo && git commit -m "Added foo"
[master (root-commit) ddff7a7] Added foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 foo
mark@lunchbox:~/example$ git checkout -b newbranch
Switched to a new branch 'newbranch'
mark@lunchbox:~/example$ touch bar && git add bar && git commit -m "Added bar"
[newbranch 7f9299a] Added bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git rm foo && git commit -m "Deleted foo"
rm 'foo'
[master 7740344] Deleted foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 foo
mark@lunchbox:~/example$ git checkout newbranch
Switched to branch 'newbranch'
mark@lunchbox:~/example$ git rm bar && git commit -m "Deleted bar"
rm 'bar'
[newbranch 873ed35] Deleted bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git merge newbranch
Already up-to-date!
Merge made by the 'recursive' strategy.
mark@lunchbox:~/example$ git log -- foo
commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log -- bar
mark@lunchbox:~/example$ git log --full-history -- foo
commit 2463e56a21e8ee529a59b63f2c6fcc9914a2b37c
Merge: 7740344 873ed35
Author: Mark Amery 
Date:   Tue Jan 12 22:51:36 2016 +0000

    Merge branch 'newbranch'

commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log --full-history -- bar
commit 873ed352c5e0f296b26d1582b3b0b2d99e40d37c
Author: Mark Amery 
Date:   Tue Jan 12 22:51:29 2016 +0000

    Deleted bar

commit 7f9299a80cc9114bf9f415e1e9a849f5d02f94ec
Author: Mark Amery 
Date:   Tue Jan 12 22:50:38 2016 +0000

    Added bar

Notice how git log -- bar in the terminal dump above resulted in literally no output; Git is "simplifying" history down into a fiction where bar never existed. git log --full-history -- bar, on the other hand, gives us the commit that created bar and the commit that deleted it.

To be clear: this issue isn't merely theoretical. I only looked into the docs and discovered the --full-history flag because git log -- some_file was failing for me in a real repository where I was trying to track a deleted file down. History simplification might sometimes be helpful when you're trying to understand how a currently-existing file came to be in its current state, but when trying to track down a file deletion it's more likely to screw you over by hiding the commit you care about. Always use the --full-history flag for this use case.

Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
  • 6
    Note that this only searches history relevant to the current branch (not 'whole repo history')... i.e. if file is not yet deleted in current branch but has been in another branch, this won't find the delete commit. You have to be on any branch _where the file has already been deleted_. Maybe is obvious when thinking about it, but it caught me out at first. – Anentropic Sep 13 '18 at 11:17
  • 2
    This answer works. But from the `git log` output itself, it's not at all obvious that the last commit has **deleted** the file. I also tried `git log --name-status --full-history -- file_name` and `git log -p --stat --full-history -- file_name`, but neither explicitly indicates that the file was removed in the latest commit. This seems like a bug. – Martin_W Dec 23 '18 at 21:13
  • @Martin_ATS `mkdir somedir && cd somedir && git init && touch foo && git add foo && git commit -m "Added foo" && git checkout -b newbranch && touch bar && git add bar && git commit -m "Added bar" && git checkout master && git rm foo && git commit -m "Deleted foo" && git checkout newbranch && git rm bar && git commit -m "Deleted bar" && git checkout master && git merge newbranch && git log --name-status --full-history -- bar` includes `D bar` and `A bar` for me in the log output with Git 2.12.2. Do you not see those lines in the output? What version do you have? – Mark Amery Dec 25 '18 at 13:29
  • `git version 2.15.1` Yes, your command sequence does report `D bar` and `A bar`. Perhaps my issue is particular to my file's history. I was tracing the history of a `.htaccess` file that got gitignore'ed and removed. I finally figured that out and added the file back. When I include `--name-status` in the `git log` command, I see two `A .htaccess` entries (since I added it back in the latest commit) but no `D .htaccess`. So it seems in some cases, even though a file has been removed from the repository, `git log` will not show an explicit `D file_name` entry. – Martin_W Jan 06 '19 at 23:21
  • @Martin_ATS Curious. I wonder if perhaps the `.htaccess` got added in a commit X but then not included in the merge commit that brought X onto master? That's the only thing I can think of that I could possibly argue *ought* to look like a file having been added and never deleted and yet still not being present. Would be interesting to try and figure out an MCVE, then figure out whether it's a Git bug, and if not, whether it's possible to tweak my answer to handle your case. – Mark Amery Jan 06 '19 at 23:24
153

You can find the last commit which deleted file as follows:

git rev-list -n 1 HEAD -- [file_path]

Further information is available here

Akif
  • 6,018
  • 3
  • 41
  • 44
96

Git log but you need to prefix the path with --

Eg:

dan-mac:test dani$ git log file1.txt
fatal: ambiguous argument 'file1.txt': unknown revision or path not in the working tree.

dan-mac:test dani$ git log -- file1.txt
 commit 0f7c4e1c36e0b39225d10b26f3dea40ad128b976
 Author: Daniel Palacio <danpal@gmail.com>
 Date:   Tue Jul 26 23:32:20 2011 -0500

 foo
fedorqui
  • 275,237
  • 103
  • 548
  • 598
daniel
  • 9,732
  • 7
  • 42
  • 57
39

I've just added a solution here (is there a way in git to list all deleted files in the repository?) for finding the commits of deleted files by using a regexp:

git log --diff-filter=D --summary | sed -n '/^commit/h;/\/some_dir\//{G;s/\ncommit \(.*\)/ \1/gp}'

This returns everything deleted within a directory named some_dir (cascading). Any sed regexp there where \/some_dir\/ is will do.

OSX (thanks to @triplee and @keif)

git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
Community
  • 1
  • 1
estani
  • 24,254
  • 2
  • 93
  • 76
  • 1
    Nice. Some mismatch under bash in OS X: `sed: 1: "/^commit/h;/\/some_dir\ ...": bad flag in substitute command: '}'` – Brent Faust Dec 08 '14 at 02:16
  • @BrentFoust It's a pitty I cannot test that... try adding a space at the end (after the braces but before the single quote), the man page online is not clear about that... – estani Dec 08 '14 at 16:18
  • Nice suggestion. But adding a space before the single quote didn't help. Neither did a space before the closing brace. – Brent Faust Dec 09 '14 at 22:22
  • 1
    BSD/OSX `sed` is apparently not always good with semicolons as command separators. Try changing them into newlines, or switch to `sed -n -e '/^commit/h' -e '\:/some_dir/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }` – tripleee Jan 07 '15 at 14:15
  • 1
    I tested it, and `git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }` worked for me on OSX. – keif Apr 05 '16 at 14:10
18

This command didn't work for me:

git log --full-history -1 -- [file path]

This is the command that worked:

git log --follow -- [file path]
Fabio Perrella
  • 403
  • 5
  • 6
7

This works for me:

git log -- **/Myfile.cs

If include --full-history switch, it will show a lot of changes have nothing to do with the file. Not sure why.

sky
  • 522
  • 8
  • 13
6

Try:

git log --stat | grep file
Eric Woodruff
  • 6,380
  • 3
  • 36
  • 33
  • 1
    Grep on its own is not going to be very useful, since it will give only the file name that was deleted. If you want to get the git hash, then you can use `grep -C 10` to get +-10 lines around the file name (which should include the git hash). – Gajus Nov 25 '20 at 10:08
  • I had the file name wrong and this helped me find the correct file. – Alexej Magura Jun 28 '21 at 21:22
2

One can do the same for a directory if one doesn't recall the exact filename. Find the commit where deletion occurred and checkout a commit before that.

git log -- the/dir/where/things/got/deleted/
nvd
  • 2,995
  • 28
  • 16