git wrapper: more careful argument stuffing
[gitweb.git] / git-format-patch.sh
index 09b635e49256ecf3fb2af7e921da76d8a580e676..1eebe857c021495b92d9e39ec1193b85ab4e980e 100755 (executable)
@@ -3,10 +3,17 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-. git-sh-setup || die "Not a git archive."
+. git-sh-setup
+
+# Force diff to run in C locale.
+LANG=C LC_ALL=C
+export LANG LC_ALL
 
 usage () {
-    echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox] [--check] [--signoff] [-<diff options>...] upstream [ our-head ]
+    echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
+    [--check] [--signoff] [-<diff options>...]
+    [--help]
+    ( from..to ... | upstream [ our-head ] )
 
 Prepare each commit with its patch since our-head forked from upstream,
 one file per patch, for e-mail submission.  Each output file is
@@ -61,6 +68,9 @@ do
     --output-directo|--output-director|--output-directory)
     case "$#" in 1) usage ;; esac; shift
     outdir="$1" ;;
+    -h|--h|--he|--hel|--help)
+        usage
+       ;;
     -*' '* | -*"$LF"* | -*'    '*)
        # Ignore diff option that has whitespace for now.
        ;;
@@ -75,25 +85,78 @@ tt)
        die '--keep-subject and --numbered are incompatible.' ;;
 esac
 
-rev1= rev2=
-case "$#" in
-2)
-    rev1="$1" rev2="$2" ;;
-1)
-    case "$1" in
-    *..*)
-       rev1=`expr "$1" : '\(.*\)\.\.'`
-       rev2=`expr "$1" : '.*\.\.\(.*\)'`
+tmp=.tmp-series$$
+trap 'rm -f $tmp-*' 0 1 2 3 15
+
+series=$tmp-series
+commsg=$tmp-commsg
+filelist=$tmp-files
+
+# Backward compatible argument parsing hack.
+#
+# Historically, we supported:
+# 1. "rev1"            is equivalent to "rev1..HEAD"
+# 2. "rev1..rev2"
+# 3. "rev1" "rev2      is equivalent to "rev1..rev2"
+#
+# We want to take a sequence of "rev1..rev2" in general.
+# Also, "rev1.." should mean "rev1..HEAD"; git-diff users are
+# familiar with that syntax.
+
+case "$#,$1$2" in
+1,?*..?*)
+       # single "rev1..rev2"
        ;;
-    *)
-        rev1="$1"
-       rev2="HEAD"
+1,?*..)
+       # single "rev1.." should mean "rev1..HEAD"
+       set x "$1"HEAD
+       shift
+       ;;
+1,*)
+       # single rev1
+       set x "$1..HEAD"
+       shift
+       ;;
+2,?*..?*)
+       # not traditional "rev1" "rev2"
+       ;;
+2,*)
+       set x "$1..$2"
+       shift
        ;;
-    esac ;;
-*)
-    usage ;;
 esac
 
+# Now we have what we want in $@
+for revpair
+do
+       case "$revpair" in
+       ?*..?*)
+               rev1=`expr "$revpair" : '\(.*\)\.\.'`
+               rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
+               ;;
+       *)
+               rev1="$revpair^"
+               rev2="$revpair"
+               ;;
+       esac
+       git-rev-parse --verify "$rev1^0" >/dev/null 2>&1 ||
+               die "Not a valid rev $rev1 ($revpair)"
+       git-rev-parse --verify "$rev2^0" >/dev/null 2>&1 ||
+               die "Not a valid rev $rev2 ($revpair)"
+       git-cherry -v "$rev1" "$rev2" |
+       while read sign rev comment
+       do
+               case "$sign" in
+               '-')
+                       echo >&2 "Merged already: $comment"
+                       ;;
+               *)
+                       echo $rev
+                       ;;
+               esac
+       done
+done >$series
+
 me=`git-var GIT_AUTHOR_IDENT | sed -e 's/>.*/>/'`
 
 case "$outdir" in
@@ -102,13 +165,6 @@ case "$outdir" in
 esac
 test -d "$outdir" || mkdir -p "$outdir" || exit
 
-tmp=.tmp-series$$
-trap 'rm -f $tmp-*' 0 1 2 3 15
-
-series=$tmp-series
-commsg=$tmp-commsg
-filelist=$tmp-files
-
 titleScript='
        /./d
        /^$/n
@@ -130,19 +186,6 @@ whosepatchScript='
        q
 }'
 
-git-cherry -v "$rev1" "$rev2" |
-while read sign rev comment
-do
-       case "$sign" in
-       '-')
-               echo >&2 "Merged already: $comment"
-               ;;
-       *)
-               echo $rev
-               ;;
-       esac
-done >$series
-
 process_one () {
        mailScript='
        /./d
@@ -199,9 +242,8 @@ Date: '"$ad"
        echo
        git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
        echo
-       git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
        git-diff-tree -p $diff_opts "$commit"
-       echo "---"
+       echo "-- "
        echo "@@GIT_VERSION@@"
 
        case "$mbox" in
@@ -229,7 +271,7 @@ do
     file=`printf '%04d-%stxt' $i "$title"`
     if test '' = "$stdout"
     then
-           echo "$file"
+           echo "$file"
            process_one >"$outdir$file"
            if test t = "$check"
            then
@@ -240,7 +282,7 @@ do
                :
            fi
     else
-           echo >&2 "$file"
+           echo >&2 "$file"
            process_one
     fi
     i=`expr "$i" + 1`