263

I want to find the most recent commit that modified a source file.

I can use git blame to see all the dates for commits by each line, but it’s difficult to see exactly which commit was the last one to touch the file.

How can I find the last commit that touched a given file in my git repository?

Zearin
  • 1,474
  • 2
  • 17
  • 36
Cory Klein
  • 51,188
  • 43
  • 183
  • 243

6 Answers6

338

git log supports looking at the history of specific files (and directories), so you can call it like this:

git log my/file.c

If you really only want to list the one most recent commit, for example to use it in a script, use the -n 1 option:

git log -n 1 --pretty=format:%H -- my/file.c

--pretty=format:%h tells git log to show only the commit hash. The -- separater stops the file name from getting interpreted as a commit name, just in case it's ambiguous.

Jo Liss
  • 30,333
  • 19
  • 121
  • 170
  • 17
    If you want to know the last time a file was modified no matter the branch, you can consider all branches by adding the `--all` option. – K. C. Aug 13 '15 at 08:00
  • I'm having to add a `--` before the filepath, e.g. `git log -- my/file.c`. – FeifanZ Mar 07 '22 at 19:35
  • note that this will work only in static environment, meaning if re-clone your repository, commit hashes will be changed. – dzona Apr 04 '23 at 12:03
78

If you just want to find the most recent commit, then you don't want git-log, you want git-rev-list, which lists the commit objects changing that file, in that commit path, starting with the most recent one (chronologically). Simply put:

git rev-list -1 <commit> <filename>

For git-rev-list in your case, you just supply:

  • The number of commits to include, or -1 for only the most recent,
  • The branch (or commit id) to start looking back from, HEAD if you are already on it, or --all if you want all known commits, and
  • The relative path to your file.

This just returns the most recent commit ID in the current branch to alter that file, ex: 215095e2e338525be0baeeebdf66bfbb304e7270

For a more complex example, you can use tag names, and even remote references, and include relative path names with wildcards, for ex:

git rev-list origin/user/bob/testbranch -1 src/bfiles/*.txt

...Which would tell you what the most recent change was to the wildcard match in that branch's history. The options for rev-list are extreme, it is one of the most important plumbing commands, so you can include or exclude by just about any criteria you can imagine.

Of course, refer to the git-rev-list(1) Manual Page.

Michael Erickson
  • 3,881
  • 2
  • 20
  • 16
  • 1
    You really did not explain why using `git-log` is inferior. – Piotr Dobrogost Jun 14 '16 at 17:47
  • 12
    I would not say inferior, just that it provides extraneous information by default. git-rev-list just returns the commit ID, which is what you want if you are going to feed the response into a script or other automation process. git-log returns information about the selected commits, first by using git-rev-list to gather the commit ids, then gathering information on each commit. If you are just going to filter out the commit information and use the ids, then you can just use git-rev-list in the first place. Since log is based on rev-list, it takes most of the same filter parameters. – Michael Erickson Nov 15 '16 at 16:24
  • 9
    `git-log` is porcelain, `git-rev-list` is plumbing. – blitzen9872 Jul 13 '17 at 08:06
  • please note that if you merged a commit from a different branch, this method will not give you the merge commit (as I had expected, because it is the commit that introduces this change to my branch) but the original commit that was merged. Just something to keep in mind. Haven't found a command to get the merge commit yet, but I'm sure there is one – SvenS Nov 16 '21 at 16:03
30

If you want to just get the hash of the latest commit to modify a specific set of files (and want to avoid awk) you can use:

git log -n 1 --pretty=format:%h -- <path>

This can be useful for getting the commit hash for subsequently using with git describe.

For example (in case it's useful for anyone)…

I create a current version id by considering the latest commit to change any source file (assuming you mark versions with tags like mycode-1.2.1):

COMMIT=$(git log -n 1 --pretty=format:%h -- *.c *.h)
if VN=$(git describe --always --abbrev=5 --match "mycode-*" $COMMIT 2>/dev/null) &&
case "$VN" in
mycode-*)
    git update-index -q --refresh
    test -z "$(git diff-index --name-only HEAD *.c *.h)" ||
    VN="$VN-mod" ;;
*) VN="mycode-unknown-g$VN" ;;
esac
then
    continue
else
VN="mycode-unknown"
fi

This produces ids like:

  • mycode-1.2.1 - when the current state of the source files corresponds to a tagged version
  • mycode-1.2.1-g3k7s2 - when the current state of the source files corresponds to commit following a tagged version
  • mycode-1.2.1-g3k7s2-mod - when the current state of the source files have been modified since the last commit following a tagged version
  • mycode-unknown - when there has not yet been a version tag created
Zearin
  • 1,474
  • 2
  • 17
  • 36
TheBamf
  • 597
  • 5
  • 8
10

I'm not sure if this is what you want but if you do a git log <thefile> to get the commits that altered that file. You can pick the topmost one. It should be the one you're looking for.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
  • 4
    if you use `git log -n1 -- ` (or pipe the output to `head -1` if you want to waste resources) you don't have to manually pick the top line (see Jo Liss's [answer](http://stackoverflow.com/questions/4784575/how-do-i-find-the-most-recent-git-commit-that-modified-a-file/4784629#4784629)) – Tobias Kienzler Apr 20 '11 at 09:37
  • 4
    Good point. I think you can also skip the `-n` and use `-1` directly. – Noufal Ibrahim Apr 20 '11 at 09:42
3

To get just the ref on one line, try:

git log -n1 --oneline <path> | awk '{print $1;}'
simhumileco
  • 31,877
  • 16
  • 137
  • 115
fastmultiplication
  • 2,951
  • 1
  • 31
  • 39
3

Once you have the SHA id of the commit you want to look at using git log FILENAME, you should be able to do git show SHA_ID_HERE to see what you did for that particular commit. You don't even need to enter the entire ID; the first 6 characters should be enough.

Joe
  • 445
  • 1
  • 5
  • 6
  • 4
    that's a bit more than the OP asked for, but FYI you can combine this into a one-liner: `git show $(git log -1 --pretty="%H" -- FILENAME)` – Tobias Kienzler Apr 20 '11 at 10:52