#!/bin/sh # Git Trach, track the state of multiple repos from a single file. # dependencies: # - git # - $EDITOR: -e # - parallel: optional, if installed will run the commands on all repos with parallel # - gt-cmd, gt-st if [ "$GIT_TRACK_REPOS" ]; then export REPOS="$GIT_TRACK_REPOS" else export REPOS="$HOME/sync/share/git-track.txt" fi # prevent file not found errors touch "$REPOS" || exit 1 which parallel >/dev/null 2>&1 && parallel=1 help() { >&2 cat <&2 printf 'No repositories added.\n' exit 1 fi } # fetch repository prettily, outputs nothing if failed fetch() { # fetch with one-line printing of progress git fetch --progress 2>/dev/null | while read -r line; do # \r\033[0K : clear current line printf >&2 '\r\033[0K%s' "$line" done } # no options if [ -z "$1" ]; then help exit 1 fi while getopts ":a:c:f:dlsheu" opt; do case "$opt" in a) if ! cd "$OPTARG" 2>/dev/null; then >&2 printf 'Not a directory.\n' exit 1 fi repo="$(git rev-parse --show-toplevel 2>/dev/null)" remote_name= if git remote show -n | grep 'origin' 2>/dev/null then remote_name="origin" else remote_name="$(git remote show -n | head -n 1)" fi remote_url="$(git remote show -n "$remote_name" 2>/dev/null | awk '/^ Fetch/ {print $NF}')" if [ -z "$repo" ] || [ -z "$remote_url" ] then >&2 printf 'Couldn'\''t add '\''%s'\'', not a git repository.\n' "$OPTARG" exit 1 fi if grep "^$repo " "$REPOS" >/dev/null 2>&1; then >&2 printf 'added already.\n' exit 1 fi printf '%s %s\n' "$repo" "$remote_url" >>"$REPOS" >&2 printf 'added.\n' ;; c) quit_when_no_repos list_repos | if [ "$parallel" ]; then parallel gt-cmd "{}" "$OPTARG" else xargs -I{} gt-cmd "{}" "$OPTARG" fi ;; d) if [ "$parallel" ]; then list_repos | parallel 'cd {}; cd "$(git rev-parse --show-toplevel || printf '\''.\\n'\'')" git pull --ff > /dev/null 2>&1 git add . git commit --all -m "checkpoint" > /dev/null 2>&1 git push > /dev/null 2>&1 printf '\''{}: done.\n'\'' | sed "s@^$HOME@~@" ' else list_repos | while read -r proj do ( cd "$proj" cd "$(git rev-parse --show-toplevel || printf '.\n')" git pull --ff > /dev/null 2>&1 git add . git commit --all -m "checkpoint" > /dev/null 2>&1 git push > /dev/null 2>&1 printf '%s: done.\n' "$proj" | sed "s@^$HOME@~@" ) done fi ;; s) quit_when_no_repos list_repos | xargs -I{} gt-st {} ;; l) quit_when_no_repos list_repos ;; e) $EDITOR "$REPOS" ;; f) REPOS="$OPTARG" ;; u) quit_when_no_repos >&2 printf 'pull:\n' if [ "$parallel" ]; then list_repos | parallel gt-cmd {} pull else list_repos | xargs -I{} gt-cmd {} pull fi >&2 printf 'push:\n' list_repos | xargs -I{} gt-st {} | awk -F: '/↑/ {print $1}' | sed "s@^~@$HOME@" | if [ "$parallel" ]; then parallel gt-cmd {} push else xargs -I{} gt-cmd {} push fi ;; h) help ;; :) >&2 printf -- '-%s requires argument\n' "$OPTARG" exit 1 ;; ?) >&2 printf -- 'Invalid option: -%s\n' "$OPTARG" exit 1 ;; esac done