Adding last modified timestamps with Git

2 min read

A common ask of Jekyll, Gatsby, and other static site generator users is, “how do I automatically set the date in YAML front matter?” Today I learned you can do just that with a Git pre-commit hook.

If your project has been setup with git init you should have a Git hooks directory with several sample files to inspect.

├── .git
│   └── hooks
│       ├── applypatch-msg.sample
│       ├── commit-msg.sample
│       ├── post-update.sample
│       ├── pre-applypatch.sample
│       ├── pre-commit.sample
│       ├── ...

You can either create a new file named pre-commit inside of the hooks directory (or rename the .sample file). Then add the following shell script:

#!/bin/sh
# Contents of .git/hooks/pre-commit
# Replace `last_modified_at` timestamp with current time

git diff --cached --name-status | grep "^M" | while read a b; do
  cat $b | sed "/---.*/,/---.*/s/^last_modified_at:.*$/last_modified_at: $(date -u "+%Y-%m-%dT%H:%M:%S")/" > tmp
  mv tmp $b
  git add $b
done

Now when you commit a modified file with Git, the value of last_modified_at will be replaced with the current time i.e., YYYY-MM-DDThh:mm:ss. If you’re using a different front matter variable for modified timestamps, adjust the script above accordingly.

Before commit After commit
last_modified_at: last_modified_at: 2021-08-04T20:34:59

I’ve always followed the convention of using date for published timestamp and last_modified_at for the modified timestamp. Mostly because core Jekyll plugins like jekyll-sitemap and jekyll-feed support that front matter value.

---
title: "My awesome Markdown post"
date: 2020-01-01
last_modified_at: 2021-08-04T20:34:59
---

Note: The only real gotcha I’ve hit with this method is making sure last_modified_at exists in the front matter. It can be a blank value, but if the variable isn’t present then no timestamp is added when the file is committed.

I’d be interested if the script could be improved on to append the date if last_modified_at hasn’t already been added, and replace the value if it has. Let me know below if you have any improves there.

I’m also not sure if this pre-commit hook is automatically installed when the Git repository is cloned. Do I need to install it on both my iMac running macOS and laptop running Windows 10? Or does it come along for the ride when push/pulling from remote?

About the author

Hi I’m Michael Rose. Just another boring, bearded, tattooed, time traveling designer from Buffalo New York. I maintain several open source projects and occassionally blog.

Glitched photo of Michael Rose with a long beard.

Interactions

4 comments

  1. Simone Silvestroni wrote on

    Brilliant, thanks. I’ve checked, and based on git-scm:

    It’s important to note that client-side hooks are not copied when you clone a repository. If your intent with these scripts is to enforce a policy, you’ll probably want to do that on the server side; see the example in An Example Git-Enforced Policy.

  2. Simone Silvestroni wrote on

    Something weird happened after I implemented the hook. Code-wise was perfect, last_modified_at worked like a charm. However, after I’ve added the same hook to my colleague’s pre-commit hook, she committed a big chunk of images, which turned all of them into 0-bytes files.

    After a test, the same happened to me, so I removed the hook and the issue went away. Did this happened to you?

  3. Michael Rose wrote on

    @Simone - I’ve only used this method to do some light testing and didn’t see any issues.

    I did come across more robust versions of precommit hooks that appeared to check against file type, which would probably get around your issue of messing with binary files like images. For example this blog post has a version that looks for modified .html files. I’m sure it could be adapted for .md.

    All that said, not sure if I completely trust either scripts 💯 and still add last modified dates in a somewhat manual way using the Insert Date String VS Code plugin to drop in a new timestamp after I touch a file.

  4. Simone Silvestroni wrote on

    Thanks for your help. Just checked that VS extension… it might be time to leave Atom for good. After I left Sublime Text for good a few years ago. And that was after I ditched Textmate 😬