DEV Community

Cover image for Update your files header using git hooks
Sérgio Araújo
Sérgio Araújo

Posted on • Updated on

Update your files header using git hooks

If was not enouth Linux Torvalds Invented Linux he also created git ...

The git hooks

There are automated actions git takes when you commit, pull etc. For me is essential having a great file header indicating when it was modified its purpuse references and even tags, so I can grep my wiki, for instance, and find out things I forget as time goes by.

The Last (Changed|Modified): line

As an example lets see what I have on the first three lines of my nvim autocommands.lua file:

-- File: ~/.config/nvim/lua/core/autocmds.lua
-- Last Change: Wed, 09 Nov 2022 19:27:15
-- vim:set ft=lua softtabstop=2 shiftwidth=2 tabstop=2 expandtab nolist:
Enter fullscreen mode Exit fullscreen mode

Changing the "Last Change" when you run a git commit

You need to have an executable file (chmod u+x file) on your repository/.git/hooks/pre-commit

In my case it goes like this:

#!/bin/sh
# Filename: ~/.config/nvim/.git/pre-commit
# Last Change: Thu, 10 Nov 2022 - 12:16
# vim:nolist conceallevel=0 softtabstop=4 shiftwidth=4 tabstop=4 expandtab ft=sh:
# References:
# https://toroid.org/git-last-modified
# https://mademistakes.com/notes/adding-last-modified-timestamps-with-git/

# NOTE: 
# This script does not have any guarantee that it
# will work correctly, make sure
# you do all the necessary tests and
# backups to avoid any hassle

modified=$(git diff --cached --name-only --diff-filter=ACMR)

[ -z $modified ] && exit 0

for f in $modified; do
    data=$(date -r $f "+%a, %d %b %Y - %T")
    sed -ri "1,7s/^(\S*\s*Last (Change|Modified):).*/\1 $data/gi" $f
    git add $f
done
Enter fullscreen mode Exit fullscreen mode

Now, every time you commit, if any of your files was modified or added git will run this script befor commiting your changes, hence updating your Last Change line.

Explaining the commands (the way we learn)

The line...

modified=$(git status --short |  awk '$1 ~ /[MA]/ {print $2}')
Enter fullscreen mode Exit fullscreen mode

... Generates an array with all modified and added files in your repo, the $1 of awk means field 1 and the tilda means: match against Regular Expressions, in this case M or A.

The -r option of date command displays the last modification time of FILE and we also add a format on which we want to get this "last modification time" using this string: "+%a, %d %b %Y - %H:%M:%S". For more you can reda the manpage for date: man date

The sed command it is like a state of art Unix command:

sed -ri "1,7s/^((\S+\s+)?Last (change|modified):).*/\1 $data/gi" $f 
Enter fullscreen mode Exit fullscreen mode

Use extended regex (avoiding) lots of backslashes, from line 1 to 7, starting for the very first character of the line ^ start a regex group () that contains any non space \S at least + followed one space \s at least one. This first group is optional because of a question mark after that ? followed by a literal Last and one literal space, followed by one of these two words (change|modified), followed by a colon :, followed by anything.

In the substitution part we get the first group (the bigger one) that contaings the (\S+\s+)? and we say, beloved sed, please use the \1 first group here as substitution followed by the value of the $data variable.

-r ................... extended regex
-i ................... edit file in place
1,7 .................. range of substitution
^ .................... start of the line
() ................... regex group
\S ................... any non space
\s ................... space
+ .................... at least one
? .................... optional
(Modified|Changed) ... modified or changed
\1 ................... repeat the first regex group content
Enter fullscreen mode Exit fullscreen mode

NOTE: To be able to use shell variables in sed you need to use double quotes.

NOTE: The gi at the end of sed command means globally substitute ignoring case.

References:

1 - https://toroid.org/git-last-modified
2 - https://toroid.org/git-last-modified

Top comments (0)