#!/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" help() { >&2 cat </dev/null | while read -r line # \r\033[0K : clear current line do >&2 printf '\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@~@" )" # absolute path cd "$repo" # replace line with status >&2 printf '\r\033[0K' status="$(git status --porcelain 2> /dev/null | awk '{print $1}' | uniq | 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 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 >&2 printf 'added already.\n' exit 2 fi printf '%s\n' "$r" >> "$repos" >&2 printf 'added.\n' ;; c) f_command=1; f_arg="$OPTARG" ;; s) f_status=1 ;; l) cat "$repos" ;; e) $EDITOR "$repos" ;; f) repos="$OPTARG" ;; h) help ;; :) >&2 printf -- '-%s requires argument\n' "$OPTARG"; exit 1 ;; ?) >&2 printf -- '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' ' ')"