Post dates that update themselves
Keeping the "Last updated" date of a post accurate is one of those chores that isn't worth doing by hand. So now a git hook does it for me. tabi, the theme I’m using, shows a “Last updated” line under a post’s title, when the post has an But if it can be automated, why not? I think tabi’s documentation links to this post on osc.garden somewhere. Its author, Óscar, is the same guy who made the tabi theme. It describes a pre-commit hook that sets the I had it on my list to set up for a while, I just never got around to it. Now with AI, that barrier is gone. The hook lives in the repository, in A few things are different from the original: The date itself is the day the file was last modified. A post that’s edited on the day it was published (which is usually the moment you’re in a panic to fix typo’s seconds after publishing) doesn’t get an This is the part of the hook that does it: The whole hook is on GitHub. Does fixing a typo deserve a new date? For me, it doesn’t really matter. I don’t do (and never will do) breaking news or live blogs, nothing time sensitive [1], so my updates will mostly boil down to fixing typos. Which is exactly why it isn’t worth the effort of doing by hand: too much work for too little value. But if it can be automated, it’s a nice to have. Anyone who really wanted to know what changed could already find it in Git, but now it’s just a bit nicer. I don’t envy the journalists that live in those kinds of environments, it seems absolutely horrible to me. ↩updated date in the frontmatter. Which I never set. Not by hand, and not at all. It feels like one of those chores that just isn’t worth doing manually: lots of hassle, little value.The hook
updated date of every post that changes in a commit, so the “Last updated” line stays accurate without me having to think about it..githooks/.What I changed
date = "YYYY-MM-DD".updated date at all.# Posts edited in this commit (modified, not newly added; no section indexes),
# collected before the image steps below rewrite any posts, so a post that only
# had its images converted doesn't get a new `updated` date.
staged=$(git diff --cached --name-only --diff-filter=M -- '*.md' ':(exclude)*_index.md')
# … the image steps …
[ -n "$staged" ] || exit 0
while IFS= read -r file; do
[ -n "$file" ] && [ -f "$file" ] || continue
# Only posts carry a `date`; pages without one are left alone.
date_line=$(grep -m 1 '^date = ' "$file") || continue
unquote() { sed -e 's/^[a-z]* = //' -e 's/[[:space:]]*$//' -e 's/^"//' -e 's/"$//'; }
published=$(printf '%s\n' "$date_line" | unquote)
last_modified=$(date -r "$file" +'%Y-%m-%d')
# A post edited on the day it was published needs no `updated` field.
[ "$published" = "$last_modified" ] && continue
updated_line=$(grep -m 1 '^updated = ' "$file")
if [ -n "$updated_line" ]; then
# Already correct: leave the file (and the index) untouched.
[ "$(printf '%s\n' "$updated_line" | unquote)" = "$last_modified" ] && continue
fi
# Match the quoting style of the file's own `date` field.
case "$date_line" in
*'"'*) new_value="\"$last_modified\"" ;;
*) new_value="$last_modified" ;;
esac
if [ -n "$updated_line" ]; then
# Replace the existing field.
awk -v v="$new_value" '
BEGIN { done = 0 }
/^updated = / && !done { print "updated = " v; done = 1; next }
{ print }
' "$file" > "$file.tmp" || error_exit "failed to rewrite $file"
else
# Add it directly below `date`.
awk -v v="$new_value" '
BEGIN { done = 0 }
{ print }
/^date = / && !done { print "updated = " v; done = 1 }
' "$file" > "$file.tmp" || error_exit "failed to rewrite $file"
fi
mv "$file.tmp" "$file" || error_exit "failed to replace $file"
git add -- "$file"
echo "pre-commit: updated = $last_modified in $file"
done <<< "$staged"What counts as an update?