#!/bin/bash # vi:ts=4 # # mkChangLog - produce a ChangeLog from git history on stdout # # SYNOPSIS # mkChangeLog [OPTION] # # DESCRIPTION # Extract commit comments and label each tag with a date # from most recent to oldest. # Default output is suitable for including in markdown files # # -c curRev - use CurRev as tag name if current rev (latest commit) has no tag # # -s stopRev - will stop the log with the specified tag # changelog will not show commit messages earlier than the stopRev tag # To indicate stopping at very first tag, use - # # -H heading - use heading instead of "CHANGELOG" for heading1 of log # # -h heading - use heading instead of "------------" for heading2 of log # # AUTHOR # Bill Perry bperrybap@opensource.billsworld.billandterrie.com # 2016-08-08 # # NOTES: # The reason for the curRev option is that when creating a changelog file that # needs to be part of a tagged revision, there is a chicken & egg problem of # how do you create the changelog for that revision and also set the tag for # the revision that includes the updated changelog file? # If you set the tag to get the changelog output to include the new tag, then # when you commit the changelog file created from the log output, there is an # additional commit that affects the log and the log file for the commit is # *after* the tag instead of being at the tag. # The answer to this dilema: "CHEAT" a bit. # So the curRev option will fake the tagname on the most recent commits since # the previous tag to be the name "curRev" even though the tag has not yet been # set. There is still one limitation the commit log message for updating the # changelog file will not be shown for the changes associated with the new tag. # There is no way to work around this. # However, the log message entry will show when the next tag is created, so it # is only the most recent tag that will be missing the commit message for the # changelog file update. # # This allows a process of: # # - generate the ChangeLog with curRev as tag about to be created # - commit ChangeLog # - tag with the tag used as curRev # # This will create a single commit as well as the desired tag pointing # to the commit that contains the log for new tag. # # pname=`basename $0` HEADING1="CHANGELOG" HEADING2="----------------------" function USAGE { printf "usage:\n" printf "$pname [option]\n" printf "\t-c curRev\n\t\tuse CurRev as tagname if current rev has no tag\n" printf "\t-s stopRev\n\t\tno log output prior to stopRev tag\n" printf "\t-H heading\n\t\tuse heading instead of \"$HEADING1\" for heading1 of log\n" printf "\t-h heading\n\t\tuse heading instead of \"$HEADING2\" for heading2 of log\n" } # check for arguments while getopts ":s:c:H:h:" opt; do case $opt in c) curRev=$OPTARG ;; s) stopRev=$OPTARG ;; H) HEADING1=$OPTARG ;; h) HEADING2=$OPTARG ;; \?) echo "$pname: invalid option: -$OPTARG" >&2 USAGE exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 USAGE exit 1 ;; esac done # if stopRev is "-" then use first tag in repo if [ "$stopRev" = "-" ] then stopRev=$(git tag -l | head -1) fi #now generate the change log # if headings are empty, don't output them if [ "$HEADING1" != "" ] then echo "$HEADING1" fi if [ "$HEADING2" != "" ] then echo "$HEADING2" fi git for-each-ref --sort='*authordate' --format='%(tag)' refs/tags |tac |grep -v '^$' | while read TAG ; do echo if [ $NEXT ];then rev=$NEXT else if [ "$curRev" != "" ] then rev=$curRev else rev=`git describe --dirty` fi fi if [ "$rev" != "$TAG" ] then echo [$rev] - `git log -1 --format=%ad --date=short $NEXT` if [ "$rev" = "$stopRev" ] then # note: the exit below exits the loop command not the script # the exit value will be the status code of the loop exit 9 fi GIT_PAGER=cat git log --no-merges --format=" * %s" $TAG..$NEXT fi NEXT=$TAG done # if loop exited because it stopped early from a stopRev, status will be non zero # so exit script if [ $? -ne 0 ] then exit 0 fi FIRST=$(git tag -l | head -1) echo echo [$FIRST] - `git log -1 --format=%ad --date=short $FIRST` if [ "$FIRST" = "$stopRev" ] then exit 0 fi # if this GIT_PAGER below is commented out then the logs for the first tag are not emitted GIT_PAGER=cat git log --no-merges --format=" * %s" $FIRST