#!/bin/bash
# thanks Carl!
set -e

usage () {
  echo "usage: $(basename "$0") [-3] ADD_EDIT.patch"
  echo
  echo "(to be used as GIT_EDITOR for 'git add --edit')"
  exit
}

diff_util=gvimdiff
[[ $DISPLAY ]] || diff_util=vimdiff

while [[ $1 = -* ]]; do
case $1 in
  -3 ) diff3=Y; shift ;;
  -v ) diff_util=vimdiff; shift ;;
  -* ) usage ;;
esac
done

[[ -f $1 ]] || usage

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT

mkdir "$tmp"/{HEAD,index,working}
topdir=$(git rev-parse --show-toplevel)

patch=$1
> "$patch"

{ git diff-index --name-only -z HEAD |
  # read NUL terminated filenames
  while IFS= read -d '' fname; do
    {
      base=${fname##*/}
      indx=$tmp/index/$base
      head=$tmp/HEAD/$base
      work=$tmp/working/$base  # <-- just a symlink
      ln -s "$topdir/$fname" "$tmp/working/"

      git show :"$fname" > "$indx"
      cp "$indx" "$indx.orig"
      if [[ $diff3 = Y ]]; then
        git show HEAD:"$fname" > "$head"
        chmod -w "$head"  # for clarity
        ( cd "$tmp"; $diff_util {working,index,HEAD}/"$base" )
      else
        ( cd "$tmp"; $diff_util {working,index}/"$base" )
      fi
      diff -U7 --label={a,b}/"$fname" "$indx.orig" "$indx" |
      awk 'NR==1 {print HDR}; 1' HDR="diff --git a/$fname b/$fname" >> "$patch"
      rm -f "$indx" "$indx.orig" "$head" "$work"
    } 0<&3
  done
} 3<&0  # preserve stdin for inner commands (esp. vimdiff)

