From e80b73bc5544672a87827c5fe3dc69fff2d3ebcc Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Sat, 23 May 2020 01:15:30 +0300 Subject: [PATCH 01/12] fixes fboender/multi-git-status#34 --- mgitstatus | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mgitstatus b/mgitstatus index 9330e36..37d4d67 100755 --- a/mgitstatus +++ b/mgitstatus @@ -89,8 +89,8 @@ while [ -n "$1" ]; do if [ "$1" = "--no-stashes" ]; then NO_STASHES=1 fi - if [ "$1" = "-d" ] || [ "$1" = "--depth" ]; then - DEPTH="$2" + if [ "$1" = "-d" ] || [ "${1%=*}" = "--depth" ]; then + [ "$1" = "-d" ] && DEPTH="$2" || DEPTH="${1#*=}" echo "$DEPTH" | grep -E "^[0-9]+$" > /dev/null 2>&1 IS_NUM="$?" if [ "$IS_NUM" -ne 0 ]; then @@ -98,7 +98,7 @@ while [ -n "$1" ]; do exit 1 fi # Shift one extra param - shift + [ "$1" = "-d" ] && shift fi shift From f2bf2df0418a50b5a16a24fb9afd3e916f37186d Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Sat, 23 May 2020 01:23:45 +0300 Subject: [PATCH 02/12] added tests --- run-tests.sh | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 run-tests.sh diff --git a/run-tests.sh b/run-tests.sh new file mode 100755 index 0000000..6642fac --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +dump(){ + echo "expected:" + echo "${1}" + echo "got:" + echo "${2}" +} + +TESTS_DIR="./tests" +rm -rf "$TESTS_DIR" 2> /dev/null +mkdir -p "$TESTS_DIR/a/b" +( +cd "$TESTS_DIR"; git init foo > /dev/null +cd a; git init bar > /dev/null +cd b; git init baz > /dev/null +) + +res=$(./mgitstatus --depth=0 "$TESTS_DIR") +#echo "$res" + +# Test 1 +expected=$(cat << EOF +./tests/a/b/baz: Uncommitted changes +./tests/a/bar: Uncommitted changes +./tests/foo: Uncommitted changes +EOF +) + +[[ "$res" = "$expected" ]] \ + && echo "Test 1: passed" \ + || { echo "Test 1: failed."; dump "$expected" "$res"; } + +echo "All tests are passed." From 068248236059d395239ba9f4c4d5ecc4ea129a3e Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Mon, 25 May 2020 21:13:44 +0300 Subject: [PATCH 03/12] added submodule handling --- mgitstatus | 56 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/mgitstatus b/mgitstatus index 37d4d67..730c2db 100755 --- a/mgitstatus +++ b/mgitstatus @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # MIT license @@ -131,15 +131,34 @@ if [ "$DEPTH" -ne 0 ]; then FIND_OPTS="$FIND_OPTS -maxdepth $DEPTH" fi +containsElement () { + local e match="$1" + shift + for e; do [[ "$e" == "$match" ]] && return 0; done + return 1 +} + # Go through positional arguments (DIRs) or '.' if no argumnets are given for DIR in "${@:-"."}"; do # We *want* to expand parameters, so disable shellcheck for this error: # shellcheck disable=SC2086 - find -L "$DIR" $FIND_OPTS -type d | while read -r PROJ_DIR - do + readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -type d -print0) + [ $DEBUG -eq 1 ] && printf 'PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" + i=0 + while :; do + #printf ' -- PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" + (("$i" > "${#PROJ_DIRS[@]}")) && break + PROJ_DIR="${PROJ_DIRS[$i]}" + i=$((i+1)) + GIT_DIR="$PROJ_DIR/.git" - GIT_CONF="$PROJ_DIR/.git/config" - + if [[ -f "$GIT_DIR" ]]; then + # This is a submodule + BARE_DIR="$(cat "$PROJ_DIR/.git" | awk '{print $2}')" + GIT_DIR="$(realpath "$PROJ_DIR/$BARE_DIR")" + fi + GIT_CONF="$GIT_DIR/config" + # Check git config for this project to see if we should ignore this repo. IGNORE=$(git config -f "$GIT_CONF" --bool mgitstatus.ignore) if [ "$IGNORE" = "true" ]; then @@ -164,11 +183,24 @@ for DIR in "${@:-"."}"; do # Do a 'git fetch' if requested if [ "$DO_FETCH" -eq 1 ]; then - git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" fetch -q >/dev/null + git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" fetch -q >/dev/null fi # Refresh the index, or we might get wrong results. - git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" update-index -q --refresh >/dev/null 2>&1 + git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" update-index -q --refresh >/dev/null 2>&1 + + # Now we know we are dealing with a git repo. Find out its submodules: + SUBMODULES=($(cd "$PROJ_DIR"; git config --file=.gitmodules --get-regexp ^^submodule.*\.path$ | cut -d " " -f 2)) + if [[ ! -z $SUBMODULES ]]; then + # printf ' | Submodule: %s\n' "${SUBMODULES[@]}" + for submodule in "${SUBMODULES[@]}"; do + SUBMODULE_PATH="${PROJ_DIR%/}/${submodule}" + if ! containsElement "$SUBMODULE_PATH" "${PROJ_DIRS[@]}"; then + #echo "...appending submodule path: $SUBMODULE_PATH" + PROJ_DIRS+=( "$SUBMODULE_PATH" ) + fi + done + fi # Find all remote branches that have been checked out and figure out if # they need a push or pull. We do this with various tests and put the name @@ -232,12 +264,10 @@ for DIR in "${@:-"."}"; do NEEDS_UPSTREAM_BRANCHES=$(printf "$NEEDS_UPSTREAM_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/") # Find out if there are unstaged, uncommitted or untracked changes - UNSTAGED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-index --quiet HEAD -- 2>/dev/null; echo $?) - UNCOMMITTED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-files --quiet --ignore-submodules --; echo $?) - UNTRACKED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" ls-files --exclude-standard --others) - cd "$(dirname "$GIT_DIR")" || exit - STASHES=$(git stash list | wc -l) - cd "$OLDPWD" || exit + UNSTAGED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" diff-index --quiet HEAD -- 2>/dev/null; echo $?) + UNCOMMITTED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" diff-files --quiet --ignore-submodules --; echo $?) + UNTRACKED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" ls-files --exclude-standard --others) + STASHES=$(cd "$PROJ_DIR"; git stash list | wc -l) # Build up the status string IS_OK=0 # 0 = Repo needs something, 1 = Repo needs nothing ('ok') From dc87768847a9041042604822699f8cf7570dc2ca Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Fri, 29 May 2020 00:57:47 +0300 Subject: [PATCH 04/12] added "--only-submodules" option --- mgitstatus | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mgitstatus b/mgitstatus index 730c2db..9aa9bd1 100755 --- a/mgitstatus +++ b/mgitstatus @@ -30,6 +30,7 @@ You can limit output with the following options: --no-uncommitted --no-untracked --no-stashes + --only-submodules EOF } @@ -45,6 +46,7 @@ NO_UPSTREAM=0 NO_UNCOMMITTED=0 NO_UNTRACKED=0 NO_STASHES=0 +ONLY_SUBMODULES=0 DEPTH=2 while [ -n "$1" ]; do @@ -89,6 +91,9 @@ while [ -n "$1" ]; do if [ "$1" = "--no-stashes" ]; then NO_STASHES=1 fi + if [ "$1" = "--only-submodules" ]; then + ONLY_SUBMODULES=1 + fi if [ "$1" = "-d" ] || [ "${1%=*}" = "--depth" ]; then [ "$1" = "-d" ] && DEPTH="$2" || DEPTH="${1#*=}" echo "$DEPTH" | grep -E "^[0-9]+$" > /dev/null 2>&1 @@ -152,8 +157,10 @@ for DIR in "${@:-"."}"; do i=$((i+1)) GIT_DIR="$PROJ_DIR/.git" + IS_SUBMODULE= if [[ -f "$GIT_DIR" ]]; then # This is a submodule + IS_SUBMODULE="yes" BARE_DIR="$(cat "$PROJ_DIR/.git" | awk '{print $2}')" GIT_DIR="$(realpath "$PROJ_DIR/$BARE_DIR")" fi @@ -202,6 +209,8 @@ for DIR in "${@:-"."}"; do done fi + [ "$IS_SUBMODULE" != "yes" ] && [ $ONLY_SUBMODULES -eq 1 ] && continue + # Find all remote branches that have been checked out and figure out if # they need a push or pull. We do this with various tests and put the name # of the branches in NEEDS_XXXX, seperated by newlines. After we're done, From e79ab99271f313cc7a34934d04380f5e3236744f Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Fri, 29 May 2020 10:48:54 +0300 Subject: [PATCH 05/12] trivial speedup --- mgitstatus | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mgitstatus b/mgitstatus index 9aa9bd1..ba21e29 100755 --- a/mgitstatus +++ b/mgitstatus @@ -148,7 +148,6 @@ for DIR in "${@:-"."}"; do # We *want* to expand parameters, so disable shellcheck for this error: # shellcheck disable=SC2086 readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -type d -print0) - [ $DEBUG -eq 1 ] && printf 'PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" i=0 while :; do #printf ' -- PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" @@ -166,12 +165,6 @@ for DIR in "${@:-"."}"; do fi GIT_CONF="$GIT_DIR/config" - # Check git config for this project to see if we should ignore this repo. - IGNORE=$(git config -f "$GIT_CONF" --bool mgitstatus.ignore) - if [ "$IGNORE" = "true" ]; then - continue - fi - # If this dir is not a repo, and WARN_NOT_REPO is 1, tell the user. if [ ! -d "$GIT_DIR" ]; then if [ "$WARN_NOT_REPO" -eq 1 ] && [ "$PROJ_DIR" != "." ]; then @@ -180,6 +173,12 @@ for DIR in "${@:-"."}"; do continue fi + # Check git config for this project to see if we should ignore this repo. + IGNORE=$(git config -f "$GIT_CONF" --bool mgitstatus.ignore) + if [ "$IGNORE" = "true" ]; then + continue + fi + [ $DEBUG -eq 1 ] && echo "${PROJ_DIR}" # Check if repo is locked From c486e6db9b8dfe475d68b7952a4bc397680a1953 Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Fri, 29 May 2020 10:49:37 +0300 Subject: [PATCH 06/12] major speedup --- mgitstatus | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mgitstatus b/mgitstatus index ba21e29..7e46f49 100755 --- a/mgitstatus +++ b/mgitstatus @@ -147,7 +147,7 @@ containsElement () { for DIR in "${@:-"."}"; do # We *want* to expand parameters, so disable shellcheck for this error: # shellcheck disable=SC2086 - readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -type d -print0) + readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -depth -name ".git" -type d -printf "%h\0" ) i=0 while :; do #printf ' -- PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" From eab9050f45ed77278632c8b068113f24dadc96e4 Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Fri, 29 May 2020 10:56:29 +0300 Subject: [PATCH 07/12] adds info output --- mgitstatus | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mgitstatus b/mgitstatus index 7e46f49..1d2e51c 100755 --- a/mgitstatus +++ b/mgitstatus @@ -21,6 +21,7 @@ deep. -f Do a 'git fetch' on each repo (slow for many repos) -c Force color output (preserve colors when using pipes) -d, --depth=2 Scan this many directories deep + --info Adds info output You can limit output with the following options: @@ -48,6 +49,7 @@ NO_UNTRACKED=0 NO_STASHES=0 ONLY_SUBMODULES=0 DEPTH=2 +INFO_OUTPUT=0 while [ -n "$1" ]; do # Stop reading when we've run out of options. @@ -94,6 +96,9 @@ while [ -n "$1" ]; do if [ "$1" = "--only-submodules" ]; then ONLY_SUBMODULES=1 fi + if [ "$1" = "--info" ]; then + INFO_OUTPUT=1 + fi if [ "$1" = "-d" ] || [ "${1%=*}" = "--depth" ]; then [ "$1" = "-d" ] && DEPTH="$2" || DEPTH="${1#*=}" echo "$DEPTH" | grep -E "^[0-9]+$" > /dev/null 2>&1 @@ -148,6 +153,8 @@ for DIR in "${@:-"."}"; do # We *want* to expand parameters, so disable shellcheck for this error: # shellcheck disable=SC2086 readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -depth -name ".git" -type d -printf "%h\0" ) + [ $INFO_OUTPUT -eq 1 ] && \ + 1>&2 echo "INFO: Examining ${#PROJ_DIRS[@]} git folders recursively..." i=0 while :; do #printf ' -- PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" From f18ea2ceaa1ca0450808ab65f2a63e3410b3eebd Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Fri, 29 May 2020 11:04:42 +0300 Subject: [PATCH 08/12] added example tool --- scripts/check-forgotten-lib-push.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100755 scripts/check-forgotten-lib-push.sh diff --git a/scripts/check-forgotten-lib-push.sh b/scripts/check-forgotten-lib-push.sh new file mode 100755 index 0000000..3eb800e --- /dev/null +++ b/scripts/check-forgotten-lib-push.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Author: ceremcem +# Description: Specifically checks the unpushed library type projects. + +OPTS= +PROJ_DIR="$1" +[[ -d "$PROJ_DIR" ]] || { echo "Usage: $(basename $0) path/to/projects/folder"; exit 1; } +cd "$PROJ_DIR" +TIMEFORMAT=%0lR +time mgitstatus --depth=6 -e --no-upstream --no-pull --only-submodules \ + --info -c $OPTS . 2>&1 \ + | stdbuf -o 0 grep -v "Permission denied" \ + | stdbuf -o 0 grep -v "File system loop detected" From f2fd677b65885cbd3baaf0d399dc881282c094ad Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Fri, 29 May 2020 11:40:41 +0300 Subject: [PATCH 09/12] improves the output order --- mgitstatus | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mgitstatus b/mgitstatus index 1d2e51c..e580136 100755 --- a/mgitstatus +++ b/mgitstatus @@ -206,11 +206,14 @@ for DIR in "${@:-"."}"; do SUBMODULES=($(cd "$PROJ_DIR"; git config --file=.gitmodules --get-regexp ^^submodule.*\.path$ | cut -d " " -f 2)) if [[ ! -z $SUBMODULES ]]; then # printf ' | Submodule: %s\n' "${SUBMODULES[@]}" + j=0 for submodule in "${SUBMODULES[@]}"; do SUBMODULE_PATH="${PROJ_DIR%/}/${submodule}" if ! containsElement "$SUBMODULE_PATH" "${PROJ_DIRS[@]}"; then #echo "...appending submodule path: $SUBMODULE_PATH" - PROJ_DIRS+=( "$SUBMODULE_PATH" ) + # PROJ_DIRS+=( "$SUBMODULE_PATH" ) # Below is the same as this, but fixes the order + PROJ_DIRS=( "${PROJ_DIRS[@]:0:$(($i+$j))}" "$SUBMODULE_PATH" "${PROJ_DIRS[@]:$(($i+$j))}" ) + j=$(($j + 1)) fi done fi From 17c35edc08dff480f134bdd90ef7ef8903cd16fe Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Sun, 31 May 2020 16:06:46 +0300 Subject: [PATCH 10/12] improved info output --- mgitstatus | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mgitstatus b/mgitstatus index e580136..c16b5f1 100755 --- a/mgitstatus +++ b/mgitstatus @@ -155,6 +155,7 @@ for DIR in "${@:-"."}"; do readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -depth -name ".git" -type d -printf "%h\0" ) [ $INFO_OUTPUT -eq 1 ] && \ 1>&2 echo "INFO: Examining ${#PROJ_DIRS[@]} git folders recursively..." + PROJ_NEED_ATTENTION=0 i=0 while :; do #printf ' -- PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" @@ -311,11 +312,15 @@ for DIR in "${@:-"."}"; do if [ "$STATUS_NEEDS" = "" ]; then IS_OK=1 STATUS_NEEDS="${STATUS_NEEDS}${C_OK}ok${C_RESET} " + else + PROJ_NEED_ATTENTION=$(($PROJ_NEED_ATTENTION + 1)) fi # Print the output, unless repo is 'ok' and -e was specified if [ "$IS_OK" -ne 1 ] || [ "$EXCLUDE_OK" -ne 1 ]; then - printf "${PROJ_DIR}: $STATUS_NEEDS\n" + [ $INFO_OUTPUT -eq 1 ] && PFX="STATUS: " || PFX= + printf "${PFX}${PROJ_DIR}: $STATUS_NEEDS\n" fi done + [ $INFO_OUTPUT -eq 1 ] && echo "INFO: ${PROJ_NEED_ATTENTION} projects need attention." done From 54cf08bcd31b8190091dfac2b24b888f944b3114 Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Sun, 31 May 2020 17:23:16 +0300 Subject: [PATCH 11/12] improved argument parsing Options can now be fed before or after target directory arguments. Any unrecognized arguments are reported instead of being silently ignored. Argument parsing block is now more compact. --- mgitstatus | 153 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 64 deletions(-) diff --git a/mgitstatus b/mgitstatus index c16b5f1..0f7f77f 100755 --- a/mgitstatus +++ b/mgitstatus @@ -36,7 +36,9 @@ You can limit output with the following options: EOF } -# Handle commandline options +# Parse command line arguments +# --------------------------- +# Initialize parameters WARN_NOT_REPO=0 EXCLUDE_OK=0 DO_FETCH=0 @@ -50,69 +52,92 @@ NO_STASHES=0 ONLY_SUBMODULES=0 DEPTH=2 INFO_OUTPUT=0 - -while [ -n "$1" ]; do - # Stop reading when we've run out of options. - [ "$(printf "%s" "$1" | cut -c 1)" != "-" ] && break - - if [ "$1" = "--version" ]; then - echo "v$VERSION" - exit 0 - fi - if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then - usage - exit 1 - fi - if [ "$1" = "-w" ]; then - WARN_NOT_REPO=1 - fi - if [ "$1" = "-e" ]; then - EXCLUDE_OK=1 - fi - if [ "$1" = "-f" ]; then - DO_FETCH=1 - fi - if [ "$1" = "-c" ]; then - FORCE_COLOR=1 - fi - if [ "$1" = "--no-push" ]; then - NO_PUSH=1 - fi - if [ "$1" = "--no-pull" ]; then - NO_PULL=1 - fi - if [ "$1" = "--no-upstream" ]; then - NO_UPSTREAM=1 - fi - if [ "$1" = "--no-uncommitted" ]; then - NO_UNCOMMITTED=1 - fi - if [ "$1" = "--no-untracked" ]; then - NO_UNTRACKED=1 - fi - if [ "$1" = "--no-stashes" ]; then - NO_STASHES=1 - fi - if [ "$1" = "--only-submodules" ]; then - ONLY_SUBMODULES=1 - fi - if [ "$1" = "--info" ]; then - INFO_OUTPUT=1 - fi - if [ "$1" = "-d" ] || [ "${1%=*}" = "--depth" ]; then - [ "$1" = "-d" ] && DEPTH="$2" || DEPTH="${1#*=}" - echo "$DEPTH" | grep -E "^[0-9]+$" > /dev/null 2>&1 - IS_NUM="$?" - if [ "$IS_NUM" -ne 0 ]; then - echo "Invalid value for 'depth' (must be a number): $DEPTH" >&2 +# --------------------------- +args_backup=("$@") +args=() +_count=1 +while :; do + key="${1:-}" + case $key in + -h|-\?|--help) + usage # Display a usage synopsis. + exit + ;; + # -------------------------------------------------------- + --version) shift + echo "v$VERSION" + exit 0 + ;; + -w) shift + WARN_NOT_REPO=1 + ;; + -e) shift + EXCLUDE_OK=1 + ;; + -f) shift + DO_FETCH=1 + ;; + -c) shift + FORCE_COLOR=1 + ;; + --no-push) shift + NO_PUSH=1 + ;; + --no-pull) shift + NO_PULL=1 + ;; + --no-upstream) shift + NO_UPSTREAM=1 + ;; + --no-uncommitted) shift + NO_UNCOMMITTED=1 + ;; + --no-untracked) shift + NO_UNTRACKED=1 + ;; + --no-stashes) shift + NO_STASHES=1 + ;; + --only-submodules) shift + ONLY_SUBMODULES=1 + ;; + --info) shift + INFO_OUTPUT=1 + ;; + -d|-d=*|--depth|--depth=*) + if [[ "$1" == *"="* ]]; then + DEPTH="${1#*=}" # remove the prefix + else + shift + DEPTH="$1" + fi + shift + echo "$DEPTH" | grep -E "^[0-9]+$" > /dev/null 2>&1 + IS_NUM="$?" + if [ "$IS_NUM" -ne 0 ]; then + echo "Invalid value for 'depth' (must be a number): ${DEPTH:-NULL}" >&2 + exit 1 + fi + ;; + # -------------------------------------------------------- + -*) # Handle unrecognized options + echo + echo "Unknown option: $1" + echo exit 1 - fi - # Shift one extra param - [ "$1" = "-d" ] && shift - fi - - shift -done + ;; + *) # Generate the new positional arguments: $arg1, $arg2, ... and ${args[@]} + if [[ ! -z ${1:-} ]]; then + declare arg$((_count++))="$1" + args+=("$1") + shift + fi + esac + [[ -z ${1:-} ]] && break +done; set -- "${args_backup[@]}" +# Use $arg1 in place of $1, $arg2 in place of $2 and so on, +# "$@" is in the original state, +# use ${args[@]} for new positional arguments if [ -t 1 ] || [ "$FORCE_COLOR" -eq 1 ]; then # Our output is not being redirected, so we can use colors. @@ -149,7 +174,7 @@ containsElement () { } # Go through positional arguments (DIRs) or '.' if no argumnets are given -for DIR in "${@:-"."}"; do +for DIR in "${args[@]:-"."}"; do # We *want* to expand parameters, so disable shellcheck for this error: # shellcheck disable=SC2086 readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -depth -name ".git" -type d -printf "%h\0" ) From 2a810121620397c2b20d9b669904d35b568b9aee Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Tue, 2 Jun 2020 00:00:32 +0300 Subject: [PATCH 12/12] added "stalled branch detection", backward compatibility by --info --- mgitstatus | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/mgitstatus b/mgitstatus index 0f7f77f..1390858 100755 --- a/mgitstatus +++ b/mgitstatus @@ -31,6 +31,7 @@ You can limit output with the following options: --no-uncommitted --no-untracked --no-stashes + --no-stalled --only-submodules EOF @@ -52,6 +53,7 @@ NO_STASHES=0 ONLY_SUBMODULES=0 DEPTH=2 INFO_OUTPUT=0 +NO_STALLED= # --------------------------- args_backup=("$@") args=() @@ -98,6 +100,9 @@ while :; do --no-stashes) shift NO_STASHES=1 ;; + --no-stalled) shift + NO_STALLED=1 + ;; --only-submodules) shift ONLY_SUBMODULES=1 ;; @@ -158,6 +163,7 @@ C_NEEDS_COMMIT="$C_RED" C_NEEDS_UPSTREAM="$C_PURPLE" C_UNTRACKED="$C_CYAN" C_STASHES="$C_YELLOW" +C_STALLED="$C_YELLOW" # Find all .git dirs, up to DEPTH levels deep. If DEPTH is 0, the scan in # infinitely deep @@ -177,14 +183,14 @@ containsElement () { for DIR in "${args[@]:-"."}"; do # We *want* to expand parameters, so disable shellcheck for this error: # shellcheck disable=SC2086 - readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -depth -name ".git" -type d -printf "%h\0" ) + readarray -d '' PROJ_DIRS < <(find -L "$DIR" $FIND_OPTS -depth -name ".git" -printf "%h\0" ) [ $INFO_OUTPUT -eq 1 ] && \ 1>&2 echo "INFO: Examining ${#PROJ_DIRS[@]} git folders recursively..." PROJ_NEED_ATTENTION=0 i=0 while :; do #printf ' -- PROJ_DIRS: %s\n' "${PROJ_DIRS[@]}" - (("$i" > "${#PROJ_DIRS[@]}")) && break + (("$i" >= "${#PROJ_DIRS[@]}")) && break PROJ_DIR="${PROJ_DIRS[$i]}" i=$((i+1)) @@ -231,13 +237,13 @@ for DIR in "${args[@]:-"."}"; do # Now we know we are dealing with a git repo. Find out its submodules: SUBMODULES=($(cd "$PROJ_DIR"; git config --file=.gitmodules --get-regexp ^^submodule.*\.path$ | cut -d " " -f 2)) if [[ ! -z $SUBMODULES ]]; then - # printf ' | Submodule: %s\n' "${SUBMODULES[@]}" + #printf ' | Submodule: %s\n' "${SUBMODULES[@]}" j=0 for submodule in "${SUBMODULES[@]}"; do SUBMODULE_PATH="${PROJ_DIR%/}/${submodule}" if ! containsElement "$SUBMODULE_PATH" "${PROJ_DIRS[@]}"; then #echo "...appending submodule path: $SUBMODULE_PATH" - # PROJ_DIRS+=( "$SUBMODULE_PATH" ) # Below is the same as this, but fixes the order + #PROJ_DIRS+=( "$SUBMODULE_PATH" ) # Below is the same as this, but fixes the order PROJ_DIRS=( "${PROJ_DIRS[@]:0:$(($i+$j))}" "$SUBMODULE_PATH" "${PROJ_DIRS[@]:$(($i+$j))}" ) j=$(($j + 1)) fi @@ -307,12 +313,15 @@ for DIR in "${args[@]:-"."}"; do NEEDS_PULL_BRANCHES=$(printf "$NEEDS_PULL_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/") NEEDS_UPSTREAM_BRANCHES=$(printf "$NEEDS_UPSTREAM_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/") + BNAME=$(cd "$PROJ_DIR"; git rev-parse --abbrev-ref HEAD) + # Find out if there are unstaged, uncommitted or untracked changes UNSTAGED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" diff-index --quiet HEAD -- 2>/dev/null; echo $?) UNCOMMITTED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" diff-files --quiet --ignore-submodules --; echo $?) UNTRACKED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" ls-files --exclude-standard --others) STASHES=$(cd "$PROJ_DIR"; git stash list | wc -l) - + STALLED=$(git --work-tree "$PROJ_DIR" --git-dir "$GIT_DIR" branch --no-merged | xargs | sed -e 's/ /,/g') + # Build up the status string IS_OK=0 # 0 = Repo needs something, 1 = Repo needs nothing ('ok') STATUS_NEEDS="" @@ -334,6 +343,14 @@ for DIR in "${args[@]:-"."}"; do if [ "$STASHES" -ne 0 ] && [ "$NO_STASHES" -eq 0 ]; then STATUS_NEEDS="${STATUS_NEEDS}${C_STASHES}$STASHES stashes${C_RESET} " fi + STALLED_COUNT=$(echo $STALLED | tr ',' ' ' | wc -w) + if [ "$STALLED_COUNT" -ne 0 ] && [[ "$BNAME" != "HEAD" ]] && [ -z "$NO_STALLED" ]; then + STATUS_NEEDS="${STATUS_NEEDS}${C_STALLED}${STALLED_COUNT} stalled ($STALLED)${C_RESET} " + ## dump the commit logs which only the other branches have + #for b in `git branch | grep -v "*"`; do + # git log --cherry-pick --oneline --no-merges --left-only ${b}...${BNAME} + #done + fi if [ "$STATUS_NEEDS" = "" ]; then IS_OK=1 STATUS_NEEDS="${STATUS_NEEDS}${C_OK}ok${C_RESET} " @@ -341,11 +358,17 @@ for DIR in "${args[@]:-"."}"; do PROJ_NEED_ATTENTION=$(($PROJ_NEED_ATTENTION + 1)) fi + # Print the output, unless repo is 'ok' and -e was specified + PFX= + BRANCH_INFO= if [ "$IS_OK" -ne 1 ] || [ "$EXCLUDE_OK" -ne 1 ]; then - [ $INFO_OUTPUT -eq 1 ] && PFX="STATUS: " || PFX= - printf "${PFX}${PROJ_DIR}: $STATUS_NEEDS\n" + if [ $INFO_OUTPUT -eq 1 ]; then + PFX="STATUS: " + BRANCH_INFO=" ${C_CYAN}@$BNAME${C_RESET}:" + fi + printf "${PFX}${PROJ_DIR}:${BRANCH_INFO} $STATUS_NEEDS\n" fi done - [ $INFO_OUTPUT -eq 1 ] && echo "INFO: ${PROJ_NEED_ATTENTION} projects need attention." + [ $INFO_OUTPUT -eq 1 ] && echo "INFO: Projects require attention: ${PROJ_NEED_ATTENTION}" done