#! /usr/bin/env bash # Commit and push a new note. # # -c # Commit only, don't push. # usage="usage: $0 [-c]" owd=`pwd` trap "{ cd $owd; exit 1; }" ERR set -o errtrace # Trap in functions. function info () { echo "$*" 1>&2; } function error () { info "$*"; exit 1; } push="y" while [ $# -gt 0 ]; do case $1 in -c) push="n" shift ;; *) error "$usage" ;; esac done if git status --porcelain | grep -q '^M '; then error "error: repository already has staged changes" fi untracked="$(git status --porcelain | sed -n -e 's/^?? \(.*\)/\1/p')" modified="$(git status --porcelain | sed -n -e 's/^ M \(.*\)/\1/p')" uc="$(echo "$untracked" | wc -w)" mc="$(echo "$modified" | wc -w)" if [ "$uc" -eq 0 -a "$mc" -eq 0 ]; then error "error: nothing untracked/modified" fi if [ "$(($uc + $mc))" -gt 1 ]; then error "error: multiple untracked/modified files" fi # Add the tracked file to index with --intent-to-add so that we can diff it # the same way as modified. The not so nice thing about this approach is that # we have to remember to reset it if things go badly. # if [ "$uc" -gt 0 ]; then git add --intent-to-add "$untracked" modified="$untracked" fi # Get the diff output skipping the header (the first four lines until the # first changeset). # diff="$(git diff -U0 | sed -n -e '/^@@/,$p')" dc="$(echo "$diff" | wc -l)" # Get the changeset. While we don't care for leading or trailing empty lines # down the line, we do want them in the count. And preserving them in program # substitution is more difficult than one would think. # cset="$(echo "$diff" | sed -n -e 's/^+\(.*\)/\1/p')" cc="$(echo "$diff" | sed -n -e 's/^+\(.*\)/\1/p' | wc -l)" # We should only have one changeset and it should only have added lines. Note # that this is always the case for a new file. # if [ "$dc" -ne "$(($cc + 1))" ]; then info "error: multiple changesets or non-add changes" git diff -U0 exit 1 fi # Get the first non-empty line which should be the header. # l= while read l || [ -n "$l" ]; do if [ -n "$l" ]; then break fi done < <(echo "$cset") # Should start with one of [-?!]. # sum="$(echo "$l" | sed -n -re 's/^[-?!] ([^[]*)( \[.*\])?$/\1/p')" if [ -z "$sum" ]; then info "error: first line does not appear to be a note header" info "info: first line is '$l'" exit 1 fi # By convention the first label is a note type (bug, feature, etc). # type="$(echo "$l" | sed -n -re 's/^[^[]*\[([^ ]*).*\]$/\1/p')" if [ -z "$type" ]; then error "error: note header does not include note type as first label" fi #@@ Maybe check known note types and warn if not one of them? # # Ok, all looks good so add, commit and push the change. # git add "$modified" git ci -m "Add $type: $sum" if [ "$push" = "y" ]; then git push fi