#!/usr/bin/env bash
#
# git-find-uncommitted-repos - recursively list repos with uncommitted changes
#
#    Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program. See <http://www.gnu.org/licenses/gpl.html>
#
# Recursively finds all git repositories in each PATH argument, runs git status
# on them, and prints the location of repositories with uncommitted changes
# Only works for conventional repositories where git dir is "<work-tree>/.git"

myname="${0##*/}"
untracked=no

invalid()  { printf "%s: invalid option: %s\n" "$myname" "$1" >&2 ; usage 1 ; }
usage() {
	cat <<-USAGE
	Usage: $myname [-u] [DIR...]
	USAGE
	if [[ "$1" ]] ; then
		cat >&2 <<- USAGE
		Try '$myname --help' for more information.
		USAGE
		exit 1
	fi
	cat <<-USAGE

	Recursively list repositories with uncommitted changes

	Options:
	  -h|--help      - show this page.
	  -u|--untracked - count untracked files as 'uncommitted'

	  DIR...         - the directories to scan, or current directory if none
	                   is specified.

	Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
	License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>
	USAGE
	exit 0
}

# Option handling
dirs=()
for arg in "$@"; do [[ "$arg" == "-h" || "$arg" == "--help" ]] && usage ; done
while (( $# )); do
	case "$1" in
	-u|--untracked) untracked=normal               ;;
	--            ) shift ; break                  ;;
	-*            ) invalid "$1"                   ;;
	*             ) dirs+=( "$1" )                 ;;
	esac
	shift
done
dirs+=( "$@" )

while read -r repo; do
	repo="$(dirname "$repo")"
	uncommitted=$(cd "$repo" && git status --short --untracked-files="$untracked")
	if [[ "$uncommitted" ]]; then echo "$repo"; fi
done < <(find "${dirs[@]}" -name .git -type d)
