As the name suggests, the modified time of a file is updated whenever the file is changed. Although regular modified times work most of the time, some situations require a more cautious approach.
For example, when using modified times as the last updated date for a published article, the date should only update if the file received substantive changes rather than structural ones. In those cases, an update should be a deliberate action.
Git repositories provide records of deliberate updates through commit logs. By retrieving the last commit date for a specific file, we can find the last date a file was purposefully updated.
Given a repository with two commits:
git log
commit 6d9fde3f6e4a9ccd8ef720bf7f95e0f9cb74b482 Author: Bob <bob@example.com> Date: Thu Mar 2 09:26:56 2023 +0100 Update file.txt [date skip] commit 4ec5e2c29eb03c082986227609310db886d55605 Author: Alice <alice@example.com> Date: Thu Mar 2 09:09:56 2023 +0100 Add file.txt
We’ll use git log
with the following options:
--format=%ad
- Format the commit message to only show the author date
--date=format:"%F %R"
- Format the returned date with
%F %R
as thestrftime
format, which shows a full date and time: -1
- Only return the last commit
git log -1 \ --format=%ad \ --date=format:"%F %R" \ file.txt
2023-03-02 09:26
In order to allow commits that update files without updating their returned modified times, filter the commits out that match a specific flag in their messages, like [skip date]
:
git log -1 \ --format=%ad \ --date=format:"%F %R" \ --grep="\[date skip\]" \ --invert-grep file.txt
2023-03-02 09:09
However, this implementation doesn’t work when the commits aren’t in chronological order. In this example, another commit is added with a date before the existing ones:
git log
commit f50c19f9c06499c5ca400729c4c5a0f858128b95 Author: Alice <alice@example.com> Date: Thu Mar 2 06:18:11 2023 +0100 Update file.txt again commit 6d9fde3f6e4a9ccd8ef720bf7f95e0f9cb74b482 Author: Bob <bob@example.com> Date: Thu Mar 2 09:26:56 2023 +0100 Update file.txt [date skip] commit 4ec5e2c29eb03c082986227609310db886d55605 Author: Alice <alice@example.com> Date: Thu Mar 2 09:09:56 2023 +0100 Add file.txt
Because the new commit is the latest one, its commit time is returned:
git log -1 \ --format=%ad \ --date=format:"%F %R" \ --grep="\[date skip\]" \ --invert-grep file.txt
2023-03-02 06:18
To remedy this, we use a trick to get the commits in date order first.
Then we’ll take the top one from the list and pass that to git show
:
git show --quiet \ --format=%ad \ --date=format:"%F %R" \ $(git log --format="%ad %H" \ --date=format:%s \ --grep="\[date skip\]"\ --invert-grep |\ sort --reverse |\ awk '{ print $2 }' |\ head -n1)
2023-03-02 09:09