Interactive Commit Sorter for Changelogs

Projects

I wrote a Bash script to sort git commits into buckets, to be used as the first step of making a change log. It supports rewording commit messages, can be stopped and resumed, and supports automatic filtering based on keywords

License: MIT

Example

$ commitsorter ~/Documents HEAD~10..HEAD

Outputting to /home/ruben/Documents/commitsorter

[bugfix / feature / csm / ssm / other / delete / reword]

Fix something (''rubenwardy'')
: b  (auto)

Add foo (''rubenwardy'')
: f

Add bnrre mispelt (''rubenwardy'')
: r

New message: Add bar (''rubenwardy'')

Add bar (''rubenwardy'')
: f

Summary:
- Bugfixes: 1
- Features: 2
- CSM     : 0
- SSM     : 0
- Others  : 0
- Deleted : 0

The Script

#!/bin/bash

if [[ $# -ne 2 ]]; then
	echo "Usage: commitsorter output REF1..REF2"
	exit 1
fi

### Define new results here ... ###
makebuckets() {
	echo -e "## Bug fixes and Improvements ##\n" > "$1/b.txt"
	echo -e "## Features ##\n" > "$1/f.txt"
	echo -e "## Client Modding ##\n" > "$1/c.txt"
	echo -e "## Server Modding ##\n" > "$1/m.txt"
	echo -e "## Other / Misc ##\n" > "$1/o.txt"
	echo -e "## Deleted ##\n" > "$1/d.txt"
}

### ... and also add them to help ###
help() {
	echo -e "[\e[4mb\e[0mugfix / \e[4mf\e[0meature / \e[4mc\e[0msm / ss\e[4mm\e[0m / \e[4mo\e[0mther / \e[4md\e[0melete / \e[4mr\e[0meword]"
}

output="$1/commitsorter"
echo "Outputting to $output"

### Uncomment to backup and start again instead of resuming ###
# if [ -d "$output" ]; then
# 	DATE=$(date +%Y_%m_%d_%H_%M_%S)
# 	backup="${output}_$DATE"
# 	echo "Backing up $output to $backup"
# 	mv "$output" "$backup"
# fi

# Create directories and buckets
mkdir -p "$1"
mkdir -p "$output"
mkdir -p "$output/cache"
if [ ! -f $output/b.txt ]; then
	makebuckets $output
fi

# Get log
entries=`git log --pretty=format:"%h %s (''%an'')" "$2"`

# Print help
echo ""
help

# Loop
IFS=$'\n'
for line in $entries
do
	hash=$(echo $line | cut -c1-7)
	message=$(echo $line | cut -c 9- )

	echo ""
	echo "$message"

	if [[ -f $output/cache/$hash ]] ; then
		input=$(cat $output/cache/$hash)
		echo -e ": $input  (already sorted)"
	elif echo $message | grep -iq "fix\(ed\)\? "; then
		echo ": b  (auto)"
		echo $message >> $output/b.txt
		echo b > $output/cache/$hash
	elif echo $message | grep -iq "translated using weblate"; then
		echo ": d  (auto)"
		echo $message >> $output/d.txt
		echo d > $output/cache/$hash
	else
		while true; do
			read -p ": " -rsn1 input
			echo $input

			LC_ALL=C # Turn off locale.
			if [[ $input == r ]] ; then
				echo ""
				read -p "New message: " line2
				if [[ ! -z $message2 ]] ; then
					line=$message2
				fi
				echo ""
				echo $message
			elif [[ $input == [a-z] ]] ; then
				if [ -f $output/$input.txt ]; then
					echo $message >> $output/$input.txt
					echo $input > $output/cache/$hash
					break
				else
					help
				fi
			else
				help
			fi
		done
	fi
done


echo ""
echo "Summary:"
for filename in $output/*.txt; do
	title=$(head -n1 $filename | sed 's/^## \([^#]*\) ##$/\1/')
	count=$(cat $filename | tail -n+2 | sed '/^\s*$/d' | wc -l)
	echo "- $title: $count"
done