#!/bin/sh # Git Trach, track the state of multiple repos from a single file. # dependencies: # - git # - $EDITOR: -e repos=$HOME/sync/share/git-track.txt # prevent file not found errors touch "$repos" || exit 1 help() { cat >&2 </dev/null | while read -r line; do # \r\033[0K : clear current line printf >&2 '\r\033[0K%s' "$line" done } # Print repositories prettily # This function function prints animations (eg. clearing the line) # to stderr and the final status line is outputted to stdout. status() { while read -r repo; do repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@")" if [ ! -d "$repo" ]; then printf '%s missing\n' "$repo_pretty" continue fi # absolute path cd "$repo" # replace line with status printf >&2 '\r\033[0K' status="$(git status --porcelain 2>/dev/null | awk '{print $1}' | sort | uniq | tr -s '?' | tr -d '\n')" remote="$(git branch -v 2>/dev/null | sed '/^*/!d;s/ahead/↑/;s/behind/↓/;s/[^↓↑]*//g')" printf '%s %s %s\n' "$repo_pretty" "$status" "$remote" done <"$repos" } # run git command in each repo # $1: command repos_cmd() { while read -r repo; do if [ ! -d "$repo" ]; then printf '%s missing\n' "$repo_pretty" continue fi repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@")" printf ''\''%s'\'' in %s' "$1" "$repo_pretty" ( cd "$repo" git "$1" >/dev/null 2>&1 [ $? -gt 0 ] && s="x" || s="o" printf '\r\033[0K%s: %s\n' "$repo_pretty" "$s" ) done <"$repos" } # no options if [ -z "$1" ]; then help exit 1 fi while getopts ":a:c:f:lshe" opt; do case "$opt" in a) cd "$OPTARG" || exit 1 r="$(git rev-parse --show-toplevel)" [ "$r" ] || exit 2 if grep "$r" "$repos" >/dev/null 2>&1; then printf >&2 'added already.\n' exit 2 fi printf '%s\n' "$r" >>"$repos" printf >&2 'added.\n' ;; c) f_command=1 f_arg="$OPTARG" ;; s) f_status=1 ;; l) cat "$repos" ;; e) $EDITOR "$repos" ;; f) repos="$OPTARG" ;; h) help ;; :) printf >&2 -- '-%s requires argument\n' "$OPTARG" exit 1 ;; ?) printf >&2 -- 'Invalid option: -%s\n' "$OPTARG" exit 1 ;; esac done # commands hereafter must happen in order [ "$(wc -l <"$repos")" -gt 0 ] || exit 0 if [ "$f_command" ]; then repos_cmd "$f_arg" fi if [ "$f_status" ]; then status fi # eval "herbe $(status | sed 's/"/\"/g;s/.*/"&"/' | tr '\n' ' ')"