Before building your site, run a Bash script like this:
make-git-author-date-db.sh
#!/usr/bin/env bash
#------------------------------------------------------------------------------
# @file
# Creates a database of Git author dates for each file in the assets directory.
#
# To use the database in a Hugo template:
#
# {{ with resources.Get "a.jpg" }}
# {{ with index site.Data.resources.git.author_dates .Name }}
# {{ $tAttribute := .Format "2006-01-02T15:04:05-07:00" }}
# {{ $tDisplay := .Format "2006-01-02 15:04:05 -07:00" }}
# <p>Last modified: <time {{ printf "datetime=%q" $tAttribute | safeHTMLAttr }}>{{ $tDisplay }}</time></p>
# {{ end }}
# {{ end }}
#
# Git uses a commit-graph file, stored in objects/info, as an auxiliary data
# structure to enhance the performance of history traversal. This optimization
# benefits commands such as git log, git blame, and git rev-list, particularly
# in repositories with extensive or intricate histories.
#
# With Git 2.24 and later, in its default configuration, Git updates the
# commit-graph whenever git-gc is run. To manually update the commit-graph:
#
# git commit-graph write --reachable --changed-paths
#
# Keep your commit-graph updated for faster script execution.
#------------------------------------------------------------------------------
main() {
# Sensible defaults; change if needed.
declare -r assets_dir=assets # no trailing slash
declare -r data_dir=data/resources # no trailing slash
declare -r outfile=GitInfo.yaml
# Leave these alone.
declare -a files
declare file
declare path
# Verify existence of assets directory.
if [[ ! -d "${assets_dir}" ]]; then
>&2 echo "Error: the ${assets_dir} directory does not exist" && exit 1
fi
# Create the data directory.
if [[ ! -d "${data_dir}" ]]; then
mkdir -p "${data_dir}" || exit 1
fi
# Clear the data file if it exists.
if [[ -f "${data_dir}/${outfile}" ]]; then
true > "${data_dir}/${outfile}"
fi
# Create the data file.
readarray -d '' files < <(find "${assets_dir}" -type f -print0)
for file in "${files[@]}"; do
path=${file#$assets_dir/}
echo "\"/${path}\": $(git log -1 --pretty=format:'%n AbbreviatedHash: "%h"%n AuthorDate: "%aI"%n AuthorEmail: "%ae"%n AuthorName: "%an"%n Hash: "%H"%n Subject: "%s"%n' "${file}")" >> "${data_dir}/${outfile}"
done
}
set -euo pipefail
main "$@"
To create a data file like this:
data/resources/GitInfo.yaml
"/shared/other/test.js":
AbbreviatedHash: "973f798"
AuthorDate: "2024-04-28T05:07:59-07:00"
AuthorEmail: "joe.mooring@veriphor.com"
AuthorName: "Joe Mooring"
Hash: "973f798a136efc3ff04ec0df4f7cd007132e28e3"
Subject: "Reorg shared files"
"/shared/office/test.xlsx":
AbbreviatedHash: "973f798"
AuthorDate: "2024-04-28T05:07:59-07:00"
AuthorEmail: "joe.mooring@veriphor.com"
AuthorName: "Joe Mooring"
Hash: "973f798a136efc3ff04ec0df4f7cd007132e28e3"
Subject: "Reorg shared files"
"/shared/office/test.docx":
AbbreviatedHash: "973f798"
AuthorDate: "2024-04-28T05:07:59-07:00"
AuthorEmail: "joe.mooring@veriphor.com"
AuthorName: "Joe Mooring"
Hash: "973f798a136efc3ff04ec0df4f7cd007132e28e3"
Subject: "Reorg shared files"
Then display a last modified date using something like this:
{{ with resources.Get "a.jpg" }}
{{ with index site.Data.resources.git.author_dates .Name }}
{{ $tAttribute := .Format "2006-01-02T15:04:05-07:00" }}
{{ $tDisplay := .Format "2006-01-02 15:04:05 -07:00" }}
<p>Last modified: <time {{ printf "datetime=%q" $tAttribute | safeHTMLAttr }}>{{ $tDisplay }}</time></p>
{{ end }}
{{ end }}
For CI/CD deployments you’ll want to commit the modified data file, so the local process is:
git add -A && git commit -m "My latest changes to the repo"
./make-git-author-date-db.sh
git add -A && git commit --amend --no-edit
git push
Or configure your deployment workflow file to run the script server side.
Performance
On an exceptionally average system, with 124 files in the assets directory, the script ran for 1.5 seconds. After garbage collection (git gc
), which updates the commit-graph file, the script ran for 0.5 seconds. Update the commit-graph file on-demand with:
git commit-graph write --reachable --changed-paths