Skip to content

Instantly share code, notes, and snippets.

@welpo
Last active July 10, 2024 23:34
Show Gist options
  • Save welpo/f5563c3b82fe247ed0e473d940a005b7 to your computer and use it in GitHub Desktop.
Save welpo/f5563c3b82fe247ed0e473d940a005b7 to your computer and use it in GitHub Desktop.
git pre-commit script to update the date of Zola's posts and compress png files
#!/usr/bin/env bash
# Requires Bash 4.0 or newer.
# This script updates the 'updated' field in the front matter of modified .md
# files setting it to their last modified date.
# It also compresses PNG files with either oxipng or optipng if available.
# Function to exit the script with an error message.
function error_exit() {
echo "ERROR: $1" >&2
exit "${2:-1}"
}
# Function to extract the date from the front matter.
function extract_date() {
local file="$1"
local field="$2"
grep -m 1 "^$field =" "$file" | sed -e "s/$field = //" -e 's/ *$//'
}
# Get the modified .md files, ignoring "_index.md" files.
mapfile -t modified_md_files < <(git diff --cached --name-only --diff-filter=M | grep -Ei '\.md$' | grep -v '_index.md$')
# Loop through each modified .md file.
for file in "${modified_md_files[@]}"; do
# Get the last modified date from the filesystem.
last_modified_date=$(date -r "$file" +'%Y-%m-%d')
# Extract the "date" field from the front matter.
date_value=$(extract_date "$file" "date")
# Skip the file if the last modified date is the same as the "date" field.
if [[ "$last_modified_date" == "$date_value" ]]; then
continue
fi
# Update the "updated" field with the last modified date.
# If the "updated" field doesn't exist, create it below the "date" field.
awk -v date_line="$last_modified_date" 'BEGIN{FS=OFS=" = "; first = 1} { if (/^date =/ && first) { print; getline; if (!/^updated =/) print "updated" OFS date_line; first=0 } if (/^updated =/ && !first) gsub(/[^ ]*$/, date_line, $2); print }' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" || error_exit "Failed to update file $file"
# Stage the changes.
git add "$file"
done
# Check if oxipng or optipng are installed.
if command -v oxipng &> /dev/null; then
png_compressor="oxipng -o max"
elif command -v optipng &> /dev/null; then
png_compressor="optipng -o 7"
fi
# If either compressor is installed…
if [[ -n "$png_compressor" ]]; then
# Get the modified or added png files.
mapfile -t png_files < <(git diff --cached --name-only --diff-filter=d | grep -Ei '\.png$')
# Loop through each png file.
for file in "${png_files[@]}"; do
# Compress the png file.
$png_compressor -- "$file" || error_exit "Failed to compress file $file"
# Stage the changes.
git add -- "$file"
done
fi
@welpo
Copy link
Author

welpo commented Apr 16, 2023

For more context, see my blog post: Zola Git Pre-Commit Hook: Updating Post Dates.

This is a Git pre-commit script that updates the 'updated' field in the front matter of modified .md files to the last modified date and losslessly compresses modified PNG files using either oxipng or optipng (in that order of preference) if available. This script can be used with static site generators like Zola to keep your front matter up to date and optimise your images.

Whenever you commit markdown or PNG files in your Git repository (e.g. your Zola site), the script will automatically update any modified .md files to include the last modified date in the front matter 'updated' field, and it will compress any modified PNG files using the available PNG compressor (oxipng or optipng).

To use the script, copy and paste it into the .git/hooks/pre-commit file in your project's root directory. If the file doesn't exist, create it and make sure it's executable by running chmod +x .git/hooks/pre-commit.

For a version without PNG compression, check out this gist which only updates the 'updated' field in the front matter of modified .md files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment