Listing files by git status

I want to know which files (perhaps Fortran source files) in a directory have never been committed to git, which ones differ from the last commit, and which ones are the same as their last commit. You can get such information with git commands, but files with a certain status are listed on successive lines. Running `bash gitc.sh *.f90` gives compact output such as

NEW garch_ged.f90 garch_laplace.f90 garch_logis.f90 garch_t.f90 temp.f90 temp_garch.f90 temp_xgarch_sim.f90 tests.f90 tests_mix.f90 tfit.f90 xchar.f90 xcumsum.f90 xenv.f90 xmean_median.f90 xprint_real.f90 xqsort.f90 xrandom.f90 xread_vec.f90 xrep.f90 xreplace.f90 xtest_mssk.f90 xutil.f90 xwindows.f90 xxenv.f90 xxprint_real.f90
DIFFERENT constants.f90 gnuplot.f90 interpret.f90 mat.f90 qsort.f90 random.f90 util.f90 xfit_t.f90 xgarch_sim.f90 xgarch_sim_nonnormal.f90 xtest_dist.f90
SAME calc.f90 garch.f90 kind.f90 stats.f90 xcalc.f90 xinterpret.f90 xnoise.f90

Here is the script. A version that uses Windows CMD is here.

#!/usr/bin/env bash
# gitc.sh: group files (current directory only) into NEW (not in HEAD), DIFFERENT (changed vs HEAD), and SAME (matches HEAD).
# usage:
#   ./gitc.sh            # all files in current directory
#   ./gitc.sh '*.f90'    # glob in current directory
#   ./gitc.sh file1 file2 ...

set -euo pipefail

new=()
diff=()
same=()

files=()

# build file list (ignore subdirectories)
if (($# == 0)); then
  shopt -s nullglob dotglob
  for f in *; do
    [[ -f $f ]] && files+=("$f")
  done
  shopt -u dotglob
elif (($# == 1)); then
  shopt -s nullglob
  for f in $1; do
    f=${f//\\//}   # windows slashes -> /
    f=${f#./}
    [[ $f == */* ]] && continue
    [[ -f $f ]] && files+=("$f")
  done
else
  for f in "$@"; do
    f=${f//\\//}
    f=${f#./}
    [[ $f == */* ]] && continue
    [[ -f $f ]] && files+=("$f")
  done
fi

((${#files[@]})) || exit 1

for f in "${files[@]}"; do
  # NEW if not present in HEAD
  if ! git cat-file -e "HEAD:$f" 2>/dev/null; then
    new+=("$f")
  else
    if git diff --quiet HEAD -- "$f" 2>/dev/null; then
      same+=("$f")
    else
      diff+=("$f")
    fi
  fi
done

if ((${#new[@]})); then
  printf 'NEW'
  printf ' %s' "${new[@]}"
  printf '\n'
fi

if ((${#diff[@]})); then
  printf 'DIFFERENT'
  printf ' %s' "${diff[@]}"
  printf '\n'
fi

if ((${#same[@]})); then
  printf 'SAME'
  printf ' %s' "${same[@]}"
  printf '\n'
fi
1 Like