git - Find commit where file was added

65,647

Solution 1

Here's simpler, "pure Git" way to do it, with no pipeline needed:

git log --diff-filter=A -- foo.js

Check the documentation. You can do the same thing for Deleted, Modified, etc.

https://git-scm.com/docs/git-log#Documentation/git-log.txt---diff-filterACDMRTUXB82308203

I have a handy alias for this, because I always forget it:

git config --global alias.whatadded 'log --diff-filter=A'

This makes it as simple as:

git whatadded -- foo.js

The below one liner will recursively search through sub directories of the $PWD for foo.js without having to supply an absolute or relative path to the file, nor will the file need to be in the same directory as the $PWD

git log --diff-filter=A -- **foo.js

Solution 2

git log --follow --find-renames=40% --oneline -- foo.js | tail -n 1

Solution 3

The following may not be of your interest, but I think it will help you in the future and is part of the debugging ecosystem in Git:

You can use git-blame to show what revision and author last modified each line of a file, especially a file annotation. Visit https://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git

For example,

git blame -L 174,190  xx.py

The -L option is to restrict the output of the annotation to lines 174 through 190, so you will see the authors and the commit hash, etc from line 174 until 190 for the file xx.py

Solution 4

If it's an alternative to do it non-programatically, this is very quick. Open gitk GUI.

gitk file

Then just scroll to the first commit

Share:
65,647

Related videos on Youtube

Zombo
Author by

Zombo

Hello world

Updated on July 08, 2022

Comments

  • Zombo
    Zombo almost 2 years

    Say I have a file foo.js that was committed some time ago. I would like to simply find the commit where this file was first added.

    After reading the answers and my own tinkering, this works for me

    git log --follow --diff-filter=A --find-renames=40% foo.js
    
    • Rainer Rillke
      Rainer Rillke almost 3 years
      That's better than any of answers as it traces renamed files.
    • Steve Chambers
      Steve Chambers over 2 years
      Think there are some edge cases where this can return more than one result e.g. when a file is added and then subsequently deleted and added again in another commit (i.e. not a rename). Seth Robinson's answer seems to handle those cases.
    • Steve Chambers
      Steve Chambers over 2 years
      Out of interest, how did you decide upon 40% for --find-renames? Seems to work quite well for me and picked up some that --follow on its own didn't, just curious...
  • Yasushi Shoji
    Yasushi Shoji over 11 years
    I'd be nice to have --follow.
  • Geo
    Geo over 10 years
    +1! However, my file was in a subfolder, so only worked after I added an asterisk in the front git log --diff-filter=A -- *subfolder/foo.js
  • Admin
    Admin over 10 years
    How does this work on files that are merged from other branches, but which weren't necessarily added to the branch being merged by the user performing the merge?
  • rossmcm
    rossmcm about 7 years
    Could you explain please what each of the operands do? I realise you have provided a link to the relevant rtfm, but a little elucidation would make your post a one-stop shop.
  • Reidel
    Reidel about 7 years
    As Pro-Git book says If you track down a bug in your code and want to know when it was introduced and why, file annotation is often your best tool. It shows you what commit was the last to modify each line of any file, so this example that I showed uses the -L option to limit the output to lines 174 through 190 and the last thing is just the target file you want to check (xx.py) in this case a python file @rossmcm
  • webbower
    webbower about 5 years
    The doc link above doesn't jump to the flag info. Maybe it changed since posted. git-scm.com/docs/git-log#Documentation/…
  • stelterd
    stelterd about 5 years
    Yep, they changed the anchor structure in the docs. Updated, thanks!
  • Stevie Howard
    Stevie Howard over 4 years
    The accepted solution did not work for me, but this did. Thanks!
  • ipatch
    ipatch over 4 years
    @geo i think i get what you're saying but not really, but i have similar use case, where i generally stay within the project root of a git directory and issue commands from there, and using the supplied one liner git log --diff-filter=A -- foo.js did not print the commit ID / hash to STDOUT in my terminal rather i had to provide the relative path to the file from the git repo root in order to get the desired results
  • Vedran Šego
    Vedran Šego almost 4 years
    I would add --oneline to this, for a more condensed list of commits.
  • Steve Chambers
    Steve Chambers over 2 years
    I've edited the answer to include both --follow and --find-renames=40% so it follows file renames and will find the original author - hope this is OK?
  • Andreas Magnusson
    Andreas Magnusson over 2 years
    Very nice, you know that you can put the -- in the alias too so you can write git whatadded foo.js?
  • stelterd
    stelterd over 2 years
    @AndreasMagnusson yes! leaving the -- out though makes the alias more usable for me as you can still add other flags if you omit the -- part as all following arguments are interpreted as file/glob expressions. Also the -- is such muscle memory before file/glob args I'd wind up typing it anyway :)