Martin
Martin

Reputation: 21

How to auto include the newest git commit metadata into the commited files?

I aim to add a rudimentary change log to the top of every file, e.g.:

# Changelog: 
# Last Modified on: 31.2.2020
# Last Modified by: Arthur Dent
# Last Modification: "After a Trillian tries, it works"
# File created: 01.01.1970

def whale2pot(args) ....

Now, in order to not have to do that manually, I would like to include the output of

git log -1

to the files concerned by this commit. (Not sure whether including the commit message is smart though..)

One way of doing this is via a bash script, which prepends the output of the above to the file(s). But this modifies the file(s), and the repo would never be actually up to date.

Hence: Is there a way to "overload" git commit or somehow sneak this in without git noticing?

Thanks in advance =)

Upvotes: 1

Views: 852

Answers (2)

Martin
Martin

Reputation: 21

After some tinkering, I chose this format (here it is for .m files):

%% ------------------------------------------------  
%  
% Created on:       <date_of_creation>  
% Author:           <author>  
%  
% Last modifier:    <modifier>  
% Last modified:    <date_of_last_mod>  
% On Branch:        <branch>  
%  
%%-------------------------------------------------

... and realized that I don't need the commit meta-data to achieve my goal. I get:

  • the dates from $(date)
  • the Author/Modifier from $(git config user.name)
  • the current branch from $(git rev-parse --abbrev-ref HEAD)

Still I followed @LeGEC's approach of having one script which does two things, as follows:

  • insert_changelog.sh: This ensures that every untracked file with a specific extension receives a changelog. Further, it fills the static information of <date_of_creation> and <author>.
  • update_changelog.sh: This script updates the latter 3 fields of every tracked and modified file.

For the time being, I run this manually before running git add <modified files>.

I append the code below. This is my first bash scripting experience so feel free to point out what could be improved <=)


insert_changelog.sh:

#!/bin/bash

#If there are no .m files for which this would apply, suppress the this notification (If i get that right)
shopt -s nullglob

#Act on untracked files 
files=($(git ls-files --others --exclude-standard))
for item in ${files[*]}
do
    #For time being, only consider matlab files
    if [[ $item == *.m ]]
    then
        #Check whether the header already exists
        read -r first_line < $item 
        first_cl_line="%% ------------------------------------------------"
        if [ "$first_line" = "$first_cl_line" ]
        then
            continue
        else
            #Include Changelog into file
            cat changelog_template.txt > tempfile
            cat $item >> tempfile 
            mv tempfile $item

            #Fill in static fields of inception date and author
            sed -i "3,4d" $item
            sed -i "2 a % Created on:       $(date)" $item
            sed -i "3 a % Author:           $(git config user.name)" $item

            #Update current changelog
            ./update_changelog.sh $item
        fi
    fi
done;

update_changelog.sh:

#!/bin/bash
USER=$(git config user.name)  
BRANCH=$(git rev-parse --abbrev-ref HEAD)  
#Remove outdated lines and replace with updated ones.  
   for item in $(git ls-files -m)  
   do  
       sed -i "5,8d" $item  
       sed -i "5 a % Last Modifier:    $USER" $item  
       sed -i "6 a % Last Modified:    $(date)" $item  
       sed -i "7 a % On Branch:        $BRANCH" $item  
       sed -i "8 a %" $item  
   done;

Upvotes: 1

LeGEC
LeGEC

Reputation: 52216

It can be surprisingly hairy to have such an obvious source of merge conflicts in your repo,
and it is very easy to extract the info from git while you browse your repo (git log -1 the/file).

Before digging into how to actually store that info in the file's content, perhaps you could settle for a handy shell shortcut, or for an outline integrated to your editor ? vscode for example has the git lens extension which gives you something pretty close (per line annotations, actually)


The creation date would be pretty static, so it could be inserted at a file's creation and kept that way ;

for the other parts of the header : I think a filter would be the closest to the right way to do it

Official docs here : gitattributes

See an explanation in this SO answer : Can git filter out certain lines before commit?

You would write two scripts :

  • one, the clean script, would replace the header lines with constant values (eg : # Last Modified : with no date)
  • the second, the smudge script, would run git log -1 and fill the lines with the desired values

The clean script will be run when staging a file, and would make sure that the blobs stored in git have a constant header, to avoid problems when merging, rebasing, etc

The smudge script will be run when checking out a file, and will write the correct content in the worktree version -- the file on disk, which you would actually open in your editor.


The main point not sorted in this answer is : the smudge script receives the file's content on stdin, not the file's name, so I don't see a clean way to run git log -1 file/name from that script yet.

Upvotes: 1

Related Questions