Expanding keywords in Git

Originally published in my blog 2009-08-11. Please note that the information can be dated.
Back to the overview.


A common migration problem with Git is that Git does not have support for expanding RCS-like keywords. Several other systems have support for, for instance, inserting the time of the last check-in into a document by adding a place-holder on the form $Date$. Git does not, and this is considered to be by design.

I understand the arguments they give and in most cases I can live without this particular functionality. But when particularly considering having my web site in Git I would very much like to have it. Most of my pages have a date stamp at the end of the page which describes the date it was last updated, and I am much too forgetful to keep it updated by myself. I first tried a method that uses filters, but that did not work out very well. After testing various options, I have solved it by using a so called pre-commit hook:

#!/bin/bash -e

# Find base commit
if git-rev-parse --verify HEAD >/dev/null 2>&1
then
  against=HEAD
else
  # Initial commit: diff against an empty tree object
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Set up Date substitution
export NOW=$(date +"%Y-%m-%d %H:%M:%S")
for file in $(git diff-index --cached --diff-filter=AM --name-only $against); do
  if git check-attr datereplace -- "$file" | grep 'datereplace: true' > /dev/null; then
    if test -f "$file"; then
      perl -w -i -e 'my $now = $ENV{"NOW"};
$now =~ s/[^-:0-9 ]//g;
while (<>)
{
 if (/\$Date:?[^\$]*\$/)
 {
   s/\$Date:?[^\$]*\$/\$Date: ${now} \$/;
 }
 print
}' "$file"
      git update-index --add "$file"
    fi
  fi
done

exit 0

I have no doubt that it can be done in a cleaner fashion, but this works to my satisfaction for my use-case, so I am happy with it for the time being.