61

What's the simplest one-liner to get the last commit date for a bunch of files in a Git repository (i.e., for each file, the date of the last commit that changed that file)?

The context for this is that I'm using other Bash commands to find a long list of files matching some criteria, and I'd like to just pipe this list into a Git command to get the last commit date for each file.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jonderry
  • 23,013
  • 32
  • 104
  • 171
  • Were you ever able to create a git alias or whatever do dump out commit dates of bunch of files? I have a parent folder with files and folders/files, etc. I want to see last time anything in that folder changed. – Terry Apr 27 '15 at 14:01
  • 3
    @terry `for i in target/*; do git log -1 --format=%ci $i; done | sort | tail -1` – David Moles May 02 '18 at 15:44

5 Answers5

89

The following command will be helpful:

git log -1 --format=%cd filename.txt

This will print the latest change date for one file. The -1 shows one log entry (the most recent), and --format=%cd shows the commit date. See the documentation for git-log for a full description of the options.

You should be able to easily extend this for a group of files.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 3
    This is helpful. Is there a better way to attach each file's name to the date than something like the following: `for x in $(some-command); do echo $x $(git log -1 --format=%cd $x); done`? – jonderry Dec 23 '11 at 02:37
  • I don't think so, since all the `%` formatting codes refer to a *commit* rather than an individual *file*. `echo` might be the most straightforward way there. – Greg Hewgill Dec 23 '11 at 02:44
  • 4
    Worth pointing out that `%ci` outputs ISO (ish) formatted dates; so you can sort them. Also `%ai` outputs the author date, rather than the committer date. – Roger Lipscombe Mar 04 '14 at 15:42
11

Slightly extending Greg's answer, git log can take multiple paths in its argument. It will then show only the commits which included those paths. Therefore, to get the latest commit for a group of files:

git log -1 --format=%cd -- fileA.txt fileB.txt fileC.txt

I'm pretty rubbish at shell scripting, so I'm not exactly sure how to construct that command via piping, but maybe that'd be a good topic for another question.

nickf
  • 537,072
  • 198
  • 649
  • 721
  • 9
    Yeah, but that returns the latest commit amongst all the files' commits, instead of the latest commit *for each file*. – Cameron Aug 20 '15 at 20:48
  • This works but sadly not inside a TravisCI environment. When TravisCI clones the repo all file dates are the date and time of the clone (today/now) and not the date and time of what is in the repo. Very frustrating. – MitchellK Oct 06 '17 at 10:50
  • I logged an issue with TravisCI about this here if anyone else is interested > https://github.com/travis-ci/travis-ci/issues/8539 – MitchellK Oct 06 '17 at 12:17
7

Use git ls-files to find git files, and then git log to format the output. But since git log will group several file together when they share same commit time, I prefer to have it process one file at a time and then sort the result.

The resulted one-liner:

for f in $(git ls-files); do git --no-pager log --color -1 --date=short --pretty=format:'%C(cyan)%ai%Creset' -- $f ; echo  " $f"; done |sort -r

If you want to add it to your .bashrc:

function gls() {
    for f in $(git ls-files); do git --no-pager log --color -1 --date=short --pretty=format:'%C(cyan)%ai%Creset' -- $f ; echo  " $f"; done |sort -r
}

Then running gls will output something like:

2019-09-30 11:42:40 -0400 a.c
2019-08-20 11:59:56 -0400 b.conf
2019-08-19 16:18:00 -0400 c.c
2019-08-19 16:17:51 -0400 d.pc

The result is in time descending order.

Penghe Geng
  • 13,286
  • 5
  • 31
  • 40
2

Here's a one liner using find (broken into several for readability, but thanks to the trailing backslashes, copy–paste should work):

find <dirs...> -name '<pattern>' <any other predicate to get what you want> \
  -exec git log -1 --format="AAA%ai NNN" '{}' \; \
  -exec echo '{}' XXX \; \
| tr \\n N | sed -e 's/AAA/\n/g' | sed -e 's/NNNN/ /g' -e 's/XXX.*//g'

The overly complex newline mangling with tr and sed is just there to get date and filename on one line, and to ignore untracked files. You have to make sure that none of your files contain those silly markers AAA XXX NNNN.

diemo
  • 171
  • 1
  • 12
2

To get the last commit date in a long(Unix epoch timestamp) format in git(for any file) use the following command.

  • Command: git log -1 --format=%ct filename.txt
  • Result: 1605094689

Note:

  1. You can specify any file along with an extension in the git project.
  2. You can visit the git-log documentation to get a more detailed description of the options.
Keshav Lodhi
  • 2,641
  • 2
  • 17
  • 23