Git keyword substitution like those in Subversion?

Git doesn’t ship with this functionality out of the box. However, there is a chapter in the Git Book on Customizing Git and one of the examples is how to use git attributes to implement a similar result.

It turns out that you can write your own filters for doing
substitutions in files on commit/checkout. These are called “clean”
and “smudge” filters. In the .gitattributes file, you can set a filter
for particular paths and then set up scripts that will process files
just before they’re checked out (“smudge”) and just before they’re
staged (“clean”). These filters can be set to do all sorts of fun
things.

There is even an example for $LastChangedDate: $:

Another interesting example gets $Date$ keyword expansion, RCS style.
To do this properly, you need a small script that takes a filename,
figures out the last commit date for this project, and inserts the
date into the file. Here is a small Ruby script that does that:

#! /usr/bin/env ruby
data = STDIN.read
last_date = `git log --pretty=format:"%ad" -1`
puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')

All the script does is get the latest commit
date from the git log command, stick that into any $Date$ strings it
sees in stdin, and print the results – it should be simple to do in
whatever language you’re most comfortable in. You can name this file
expand_date and put it in your path. Now, you need to set up a filter
in Git (call it dater) and tell it to use your expand_date filter to
smudge the files on checkout. You’ll use a Perl expression to clean
that up on commit:

$ git config filter.dater.smudge expand_date
$ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'

This Perl snippet strips out anything it sees in a $Date$ string, to
get back to where you started. Now that your filter is ready, you can
test it by setting up a Git attribute for that file that engages the
new filter and creating a file with your $Date$ keyword:

date*.txt filter=dater
$ echo '# $Date$' > date_test.txt If you commit

those changes and check out the file again, you see the keyword
properly substituted:

$ git add date_test.txt .gitattributes
$ git commit -m "Testing date expansion in Git"
$ rm date_test.txt
$ git checkout date_test.txt
$ cat date_test.txt
# $Date: Tue Apr 21 07:26:52 2009 -0700$

You can see how powerful this technique can be for customized applications. You have to be careful,
though, because the .gitattributes file is committed and passed around
with the project, but the driver (in this case, dater) isn’t, so it
won’t work everywhere. When you design these filters, they should be
able to fail gracefully and have the project still work properly.

Leave a Comment