aboutsummaryrefslogtreecommitdiff
path: root/add
diff options
context:
space:
mode:
Diffstat (limited to 'add')
-rwxr-xr-xadd113
1 files changed, 113 insertions, 0 deletions
diff --git a/add b/add
new file mode 100755
index 0000000..b99da32
--- /dev/null
+++ b/add
@@ -0,0 +1,113 @@
+#! /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" -gt 0 -a "$mc" -gt 0 ]; 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