Merge branch 'ph/parseopt-sh'
authorJunio C Hamano <gitster@pobox.com>
Sun, 18 Nov 2007 05:39:37 +0000 (21:39 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 18 Nov 2007 05:39:37 +0000 (21:39 -0800)
* ph/parseopt-sh:
git-quiltimport.sh fix --patches handling
git-am: -i does not take a string parameter.
sh-setup: don't let eval output to be shell-expanded.
git-sh-setup: fix parseopt `eval` string underquoting
Give git-am back the ability to add Signed-off-by lines.
git-rev-parse --parseopt
scripts: Add placeholders for OPTIONS_SPEC
Migrate git-repack.sh to use git-rev-parse --parseopt
Migrate git-quiltimport.sh to use git-rev-parse --parseopt
Migrate git-checkout.sh to use git-rev-parse --parseopt --keep-dashdash
Migrate git-instaweb.sh to use git-rev-parse --parseopt
Migrate git-merge.sh to use git-rev-parse --parseopt
Migrate git-am.sh to use git-rev-parse --parseopt
Migrate git-clone to use git-rev-parse --parseopt
Migrate git-clean.sh to use git-rev-parse --parseopt.
Update git-sh-setup(1) to allow transparent use of git-rev-parse --parseopt
Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts.

23 files changed:
Documentation/git-rev-parse.txt
builtin-rev-parse.c
git-am.sh
git-bisect.sh
git-checkout.sh
git-clean.sh
git-clone.sh
git-commit.sh
git-filter-branch.sh
git-instaweb.sh
git-lost-found.sh
git-merge.sh
git-mergetool.sh
git-pull.sh
git-quiltimport.sh
git-rebase--interactive.sh
git-rebase.sh
git-repack.sh
git-request-pull.sh
git-sh-setup.sh
git-stash.sh
git-submodule.sh
git.c
index 4758c33dee53b21c0e8a489f0da11a30c63cbf48..329fce0aab417e5fe02845bd21b693f5200b3634 100644 (file)
@@ -23,6 +23,13 @@ distinguish between them.
 
 OPTIONS
 -------
+--parseopt::
+       Use `git-rev-parse` in option parsing mode (see PARSEOPT section below).
+
+--keep-dash-dash::
+       Only meaningful in `--parseopt` mode. Tells the option parser to echo
+       out the first `--` met instead of skipping it.
+
 --revs-only::
        Do not output flags and parameters not meant for
        `git-rev-list` command.
@@ -288,10 +295,75 @@ Here are a handful examples:
    C^@              I J F
    F^! D            G H D F
 
+PARSEOPT
+--------
+
+In `--parseopt` mode, `git-rev-parse` helps massaging options to bring to shell
+scripts the same facilities C builtins have. It works as an option normalizer
+(e.g. splits single switches aggregate values), a bit like `getopt(1)` does.
+
+It takes on the standard input the specification of the options to parse and
+understand, and echoes on the standard output a line suitable for `sh(1)` `eval`
+to replace the arguments with normalized ones.  In case of error, it outputs
+usage on the standard error stream, and exits with code 129.
+
+Input Format
+~~~~~~~~~~~~
+
+`git-rev-parse --parseopt` input format is fully text based. It has two parts,
+separated by a line that contains only `--`. The lines before the separator
+(should be more than one) are used for the usage.
+The lines after the separator describe the options.
+
+Each line of options has this format:
+
+------------
+<opt_spec><arg_spec>? SP+ help LF
+------------
+
+`<opt_spec>`::
+       its format is the short option character, then the long option name
+       separated by a comma. Both parts are not required, though at least one
+       is necessary. `h,help`, `dry-run` and `f` are all three correct
+       `<opt_spec>`.
+
+`<arg_spec>`::
+       an `<arg_spec>` tells the option parser if the option has an argument
+       (`=`), an optional one (`?` though its use is discouraged) or none
+       (no `<arg_spec>` in that case).
+
+The remainder of the line, after stripping the spaces, is used
+as the help associated to the option.
+
+Blank lines are ignored, and lines that don't match this specification are used
+as option group headers (start the line with a space to create such
+lines on purpose).
+
+Example
+~~~~~~~
+
+------------
+OPTS_SPEC="\
+some-command [options] <args>...
+
+some-command does foo and bar!
+--
+h,help    show the help
+
+foo       some nifty option --foo
+bar=      some cool option --bar with an argument
+
+  An option group Header
+C?        option C with an optional argument"
+
+eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
+------------
+
+
 Author
 ------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Written by Linus Torvalds <torvalds@osdl.org> .
+Junio C Hamano <junkio@cox.net> and Pierre Habouzit <madcoder@debian.org>
 
 Documentation
 --------------
index 8d78b69c902a99738cfc337222ba71493ff45370..d1038a0e66edf728fbba9476b3b9f443647c612c 100644 (file)
@@ -8,6 +8,7 @@
 #include "refs.h"
 #include "quote.h"
 #include "builtin.h"
+#include "parse-options.h"
 
 #define DO_REVS                1
 #define DO_NOREV       2
@@ -209,13 +210,138 @@ static int try_difference(const char *arg)
        return 0;
 }
 
+static int parseopt_dump(const struct option *o, const char *arg, int unset)
+{
+       struct strbuf *parsed = o->value;
+       if (unset)
+               strbuf_addf(parsed, " --no-%s", o->long_name);
+       else if (o->short_name)
+               strbuf_addf(parsed, " -%c", o->short_name);
+       else
+               strbuf_addf(parsed, " --%s", o->long_name);
+       if (arg) {
+               strbuf_addch(parsed, ' ');
+               sq_quote_buf(parsed, arg);
+       }
+       return 0;
+}
+
+static const char *skipspaces(const char *s)
+{
+       while (isspace(*s))
+               s++;
+       return s;
+}
+
+static int cmd_parseopt(int argc, const char **argv, const char *prefix)
+{
+       static int keep_dashdash = 0;
+       static char const * const parseopt_usage[] = {
+               "git-rev-parse --parseopt [options] -- [<args>...]",
+               NULL
+       };
+       static struct option parseopt_opts[] = {
+               OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
+                                       "keep the `--` passed as an arg"),
+               OPT_END(),
+       };
+
+       struct strbuf sb, parsed;
+       const char **usage = NULL;
+       struct option *opts = NULL;
+       int onb = 0, osz = 0, unb = 0, usz = 0;
+
+       strbuf_init(&parsed, 0);
+       strbuf_addstr(&parsed, "set --");
+       argc = parse_options(argc, argv, parseopt_opts, parseopt_usage,
+                            PARSE_OPT_KEEP_DASHDASH);
+       if (argc < 1 || strcmp(argv[0], "--"))
+               usage_with_options(parseopt_usage, parseopt_opts);
+
+       strbuf_init(&sb, 0);
+       /* get the usage up to the first line with a -- on it */
+       for (;;) {
+               if (strbuf_getline(&sb, stdin, '\n') == EOF)
+                       die("premature end of input");
+               ALLOC_GROW(usage, unb + 1, usz);
+               if (!strcmp("--", sb.buf)) {
+                       if (unb < 1)
+                               die("no usage string given before the `--' separator");
+                       usage[unb] = NULL;
+                       break;
+               }
+               usage[unb++] = strbuf_detach(&sb, NULL);
+       }
+
+       /* parse: (<short>|<short>,<long>|<long>)[=?]? SP+ <help> */
+       while (strbuf_getline(&sb, stdin, '\n') != EOF) {
+               const char *s;
+               struct option *o;
+
+               if (!sb.len)
+                       continue;
+
+               ALLOC_GROW(opts, onb + 1, osz);
+               memset(opts + onb, 0, sizeof(opts[onb]));
+
+               o = &opts[onb++];
+               s = strchr(sb.buf, ' ');
+               if (!s || *sb.buf == ' ') {
+                       o->type = OPTION_GROUP;
+                       o->help = xstrdup(skipspaces(s));
+                       continue;
+               }
+
+               o->type = OPTION_CALLBACK;
+               o->help = xstrdup(skipspaces(s));
+               o->value = &parsed;
+               o->callback = &parseopt_dump;
+               switch (s[-1]) {
+               case '=':
+                       s--;
+                       break;
+               case '?':
+                       o->flags = PARSE_OPT_OPTARG;
+                       s--;
+                       break;
+               default:
+                       o->flags = PARSE_OPT_NOARG;
+                       break;
+               }
+
+               if (s - sb.buf == 1) /* short option only */
+                       o->short_name = *sb.buf;
+               else if (sb.buf[1] != ',') /* long option only */
+                       o->long_name = xmemdupz(sb.buf, s - sb.buf);
+               else {
+                       o->short_name = *sb.buf;
+                       o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
+               }
+       }
+       strbuf_release(&sb);
+
+       /* put an OPT_END() */
+       ALLOC_GROW(opts, onb + 1, osz);
+       memset(opts + onb, 0, sizeof(opts[onb]));
+       argc = parse_options(argc, argv, opts, usage,
+                            keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
+
+       strbuf_addf(&parsed, " --");
+       sq_quote_argv(&parsed, argv, argc, 0);
+       puts(parsed.buf);
+       return 0;
+}
+
 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 {
        int i, as_is = 0, verify = 0;
        unsigned char sha1[20];
 
-       git_config(git_default_config);
+       if (argc > 1 && !strcmp("--parseopt", argv[1]))
+               return cmd_parseopt(argc - 1, argv + 1, prefix);
 
+       prefix = setup_git_directory();
+       git_config(git_default_config);
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
index 2514d07de2ea89598499a35e3e4a2fcc9096bbec..4126f0e857bad273d6f44cabe34565de860bd119 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -2,11 +2,26 @@
 #
 # Copyright (c) 2005, 2006 Junio C Hamano
 
-USAGE='[--signoff] [--dotest=<dir>] [--keep] [--utf8 | --no-utf8]
-  [--3way] [--interactive] [--binary]
-  [--whitespace=<option>] [-C<n>] [-p<n>]
-  <mbox>|<Maildir>...
-  or, when resuming [--skip | --resolved]'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-am [options] <mbox>|<Maildir>...
+git-am [options] --resolved
+git-am [options] --skip
+--
+d,dotest=       use <dir> and not .dotest
+i,interactive   run interactively
+b,binary        pass --allo-binary-replacement to git-apply
+3,3way          allow fall back on 3way merging if needed
+s,signoff       add a Signed-off-by line to the commit message
+u,utf8          recode into utf8 (default)
+k,keep          pass -k flagg to git-mailinfo
+whitespace=     pass it through git-apply
+C=              pass it through git-apply
+p=              pass it through git-apply
+resolvemsg=     override error message when patch failure occurs
+r,resolved      to be used after a patch failure
+skip            skip the current patch"
+
 . git-sh-setup
 set_reflog_action am
 require_work_tree
@@ -110,49 +125,38 @@ git_apply_opt=
 while test $# != 0
 do
        case "$1" in
-       -d=*|--d=*|--do=*|--dot=*|--dote=*|--dotes=*|--dotest=*)
-       dotest=`expr "z$1" : 'z-[^=]*=\(.*\)'`; shift ;;
-       -d|--d|--do|--dot|--dote|--dotes|--dotest)
-       case "$#" in 1) usage ;; esac; shift
-       dotest="$1"; shift;;
-
-       -i|--i|--in|--int|--inte|--inter|--intera|--interac|--interact|\
-       --interacti|--interactiv|--interactive)
-       interactive=t; shift ;;
-
-       -b|--b|--bi|--bin|--bina|--binar|--binary)
-       binary=t; shift ;;
-
-       -3|--3|--3w|--3wa|--3way)
-       threeway=t; shift ;;
-       -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-       sign=t; shift ;;
-       -u|--u|--ut|--utf|--utf8)
-       utf8=t; shift ;; # this is now default
-       --no-u|--no-ut|--no-utf|--no-utf8)
-       utf8=; shift ;;
-       -k|--k|--ke|--kee|--keep)
-       keep=t; shift ;;
-
-       -r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
-       resolved=t; shift ;;
-
-       --sk|--ski|--skip)
-       skip=t; shift ;;
-
-       --whitespace=*|-C*|-p*)
-       git_apply_opt="$git_apply_opt $1"; shift ;;
-
-       --resolvemsg=*)
-       resolvemsg=${1#--resolvemsg=}; shift ;;
-
+       -i|--interactive)
+               interactive=t ;;
+       -b|--binary)
+               binary=t ;;
+       -3|--3way)
+               threeway=t ;;
+       -s|--signoff)
+               sign=t ;;
+       -u|--utf8)
+               utf8=t ;; # this is now default
+       --no-utf8)
+               utf8= ;;
+       -k|--keep)
+               keep=t ;;
+       -r|--resolved)
+               resolved=t ;;
+       --skip)
+               skip=t ;;
+       -d|--dotest)
+               shift; dotest=$1;;
+       --resolvemsg)
+               shift; resolvemsg=$1 ;;
+       --whitespace)
+               git_apply_opt="$git_apply_opt $1=$2"; shift ;;
+       -C|-p)
+               git_apply_opt="$git_apply_opt $1$2"; shift ;;
        --)
-       shift; break ;;
-       -*)
-       usage ;;
+               shift; break ;;
        *)
-       break ;;
+               usage ;;
        esac
+       shift
 done
 
 # If the dotest directory exists, but we have finished applying all the
index 1ed44e56ad5021a74b2a0ec3e91849e55d4a67ce..3aac8164c62c1f4af8df76832322df9f25a05b38 100755 (executable)
@@ -22,6 +22,7 @@ git bisect log
 git bisect run <cmd>...
         use <cmd>... to automatically bisect.'
 
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
index 89939206732849e968fabaf9128597c87f18f5c7..c00cedd4837577647e369bd398fb3f6635674544 100755 (executable)
@@ -1,6 +1,16 @@
 #!/bin/sh
 
-USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+OPTIONS_KEEPDASHDASH=t
+OPTIONS_SPEC="\
+git-branch [options] [<branch>] [<paths>...]
+--
+b=          create a new branch started at <branch>
+l           create the new branchs reflog
+track       tells if the new branch should track the remote branch
+f           proceed even if the index or working tree is not HEAD
+m           performa  three-way merge on local modifications if needed
+q,quiet     be quiet
+"
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 require_work_tree
@@ -20,13 +30,12 @@ quiet=
 v=-v
 LF='
 '
-while [ "$#" != "0" ]; do
-    arg="$1"
-    shift
-    case "$arg" in
-       "-b")
-               newbranch="$1"
+
+while test $# != 0; do
+       case "$1" in
+       -b)
                shift
+               newbranch="$1"
                [ -z "$newbranch" ] &&
                        die "git checkout: -b needs a branch name"
                git show-ref --verify --quiet -- "refs/heads/$newbranch" &&
@@ -34,64 +43,54 @@ while [ "$#" != "0" ]; do
                git check-ref-format "heads/$newbranch" ||
                        die "git checkout: we do not like '$newbranch' as a branch name."
                ;;
-       "-l")
+       -l)
                newbranch_log=-l
                ;;
-       "--track"|"--no-track")
-               track="$arg"
+       --track|--no-track)
+               track="$1"
                ;;
-       "-f")
+       -f)
                force=1
                ;;
        -m)
                merge=1
                ;;
-       "-q")
+       -q|--quiet)
                quiet=1
                v=
                ;;
        --)
+               shift
                break
                ;;
-       -*)
-               usage
-               ;;
        *)
-               if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
-               then
-                       if [ -z "$rev" ]; then
-                               echo "unknown flag $arg"
-                               exit 1
-                       fi
-                       new_name="$arg"
-                       if git show-ref --verify --quiet -- "refs/heads/$arg"
-                       then
-                               rev=$(git rev-parse --verify "refs/heads/$arg^0")
-                               branch="$arg"
-                       fi
-                       new="$rev"
-               elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
-               then
-                       # checking out selected paths from a tree-ish.
-                       new="$rev"
-                       new_name="$arg^{tree}"
-                       branch=
-               else
-                       new=
-                       new_name=
-                       branch=
-                       set x "$arg" "$@"
-                       shift
-               fi
-               case "$1" in
-               --)
-                       shift ;;
-               esac
-               break
+               usage
                ;;
-    esac
+       esac
+       shift
 done
 
+arg="$1"
+if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
+then
+       [ -z "$rev" ] && die "unknown flag $arg"
+       new_name="$arg"
+       if git show-ref --verify --quiet -- "refs/heads/$arg"
+       then
+               rev=$(git rev-parse --verify "refs/heads/$arg^0")
+               branch="$arg"
+       fi
+       new="$rev"
+       shift
+elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
+then
+       # checking out selected paths from a tree-ish.
+       new="$rev"
+       new_name="$arg^{tree}"
+       shift
+fi
+[ "$1" = "--" ] && shift
+
 case "$newbranch,$track" in
 ,--*)
        die "git checkout: --track and --no-track require -b"
@@ -138,8 +137,8 @@ Did you intend to checkout '$@' which can not be resolved as commit?"
        git ls-files -- "$@" |
        git checkout-index -f -u --stdin
 
-        # Run a post-checkout hook -- the HEAD does not change so the
-        # current HEAD is passed in for both args
+       # Run a post-checkout hook -- the HEAD does not change so the
+       # current HEAD is passed in for both args
        if test -x "$GIT_DIR"/hooks/post-checkout; then
            "$GIT_DIR"/hooks/post-checkout $old $old 0
        fi
@@ -294,5 +293,5 @@ fi
 
 # Run a post-checkout hook
 if test -x "$GIT_DIR"/hooks/post-checkout; then
-        "$GIT_DIR"/hooks/post-checkout $old $new 1
+       "$GIT_DIR"/hooks/post-checkout $old $new 1
 fi
index ad68595fbf313c1cab7de565e6d44f2c87aff384..01c95e9fe8a19afcf331ed5ffd47eea478886213 100755 (executable)
@@ -3,16 +3,22 @@
 # Copyright (c) 2005-2006 Pavel Roskin
 #
 
-USAGE="[-d] [-f] [-n] [-q] [-x | -X] [--] <paths>..."
-LONG_USAGE='Clean untracked files from the working directory
-       -d      remove directories as well
-       -f      override clean.requireForce and clean anyway
-       -n      don'\''t remove anything, just show what would be done
-       -q      be quiet, only report errors
-       -x      remove ignored files as well
-       -X      remove only ignored files
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-clean [options] <paths>...
+
+Clean untracked files from the working directory
+
 When optional <paths>... arguments are given, the paths
-affected are further limited to those that match them.'
+affected are further limited to those that match them.
+--
+d remove directories as well
+f override clean.requireForce and clean anyway
+n don't remove anything, just show what would be done
+q be quiet, only report errors
+x remove ignored files as well
+X remove only ignored files"
+
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
 require_work_tree
@@ -56,11 +62,9 @@ do
                shift
                break
                ;;
-       -*)
-               usage
-               ;;
        *)
-               break
+               usage # should not happen
+               ;;
        esac
        shift
 done
@@ -77,9 +81,9 @@ case "$disabled" in
        ;;
 esac
 
-case "$ignored,$ignoredonly" in
-       1,1) usage;;
-esac
+if [ "$ignored,$ignoredonly" = "1,1" ]; then
+       die "-x and -X cannot be set together"
+fi
 
 if [ -z "$ignored" ]; then
        excl="--exclude-per-directory=.gitignore"
index 3f006936085cedcdca436455643b05d2198e3606..24ad179bbda69ecf68e49896c3c018425b645461 100755 (executable)
@@ -8,15 +8,36 @@
 # See git-sh-setup why.
 unset CDPATH
 
+OPTIONS_SPEC="\
+git-clone [options] [--] <repo> [<dir>]
+--
+n,no-checkout        don't create a checkout
+bare                 create a bare repository
+naked                create a bare repository
+l,local              to clone from a local repository
+no-hardlinks         don't use local hardlinks, always copy
+s,shared             setup as a shared repository
+template=            path to the template directory
+q,quiet              be quiet
+reference=           reference repository
+o,origin=            use <name> instead of 'origin' to track upstream
+u,upload-pack=       path to git-upload-pack on the remote
+depth=               create a shallow clone of that depth
+
+use-separate-remote  compatibility, do not use
+no-separate-remote   compatibility, do not use"
+
 die() {
        echo >&2 "$@"
        exit 1
 }
 
 usage() {
-       die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] [--] <repo> [<dir>]"
+       exec "$0" -h
 }
 
+eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+
 get_repo_base() {
        (
                cd "`/bin/pwd`" &&
@@ -106,67 +127,57 @@ depth=
 no_progress=
 local_explicitly_asked_for=
 test -t 1 || no_progress=--no-progress
-while
-       case "$#,$1" in
-       0,*) break ;;
-       *,-n|*,--no|*,--no-|*,--no-c|*,--no-ch|*,--no-che|*,--no-chec|\
-       *,--no-check|*,--no-checko|*,--no-checkou|*,--no-checkout)
-         no_checkout=yes ;;
-       *,--na|*,--nak|*,--nake|*,--naked|\
-       *,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
-       *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local)
-         local_explicitly_asked_for=yes
-         use_local_hardlink=yes ;;
-       *,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\
-       *,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks)
-         use_local_hardlink=no ;;
-        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
-          local_shared=yes; ;;
-       1,--template) usage ;;
-       *,--template)
+
+while test $# != 0
+do
+       case "$1" in
+       -n|--no-checkout)
+               no_checkout=yes ;;
+       --naked|--bare)
+               bare=yes ;;
+       -l|--local)
+               local_explicitly_asked_for=yes
+               use_local_hardlink=yes
+               ;;
+       --no-hardlinks)
+               use_local_hardlink=no ;;
+       -s|--shared)
+               local_shared=yes ;;
+       --template)
                shift; template="--template=$1" ;;
-       *,--template=*)
-         template="$1" ;;
-       *,-q|*,--quiet) quiet=-q ;;
-       *,--use-separate-remote) ;;
-       *,--no-separate-remote)
+       -q|--quiet)
+               quiet=-q ;;
+       --use-separate-remote|--no-separate-remote)
                die "clones are always made with separate-remote layout" ;;
-       1,--reference) usage ;;
-       *,--reference)
+       --reference)
                shift; reference="$1" ;;
-       *,--reference=*)
-               reference=`expr "z$1" : 'z--reference=\(.*\)'` ;;
-       *,-o|*,--or|*,--ori|*,--orig|*,--origi|*,--origin)
-               case "$2" in
+       -o,--origin)
+               shift;
+               case "$1" in
                '')
                    usage ;;
                */*)
-                   die "'$2' is not suitable for an origin name"
+                   die "'$1' is not suitable for an origin name"
                esac
-               git check-ref-format "heads/$2" ||
-                   die "'$2' is not suitable for a branch name"
+               git check-ref-format "heads/$1" ||
+                   die "'$1' is not suitable for a branch name"
                test -z "$origin_override" ||
                    die "Do not give more than one --origin options."
                origin_override=yes
-               origin="$2"; shift
+               origin="$1"
                ;;
-       1,-u|1,--upload-pack) usage ;;
-       *,-u|*,--upload-pack)
+       -u|--upload-pack)
                shift
                upload_pack="--upload-pack=$1" ;;
-       *,--upload-pack=*)
-               upload_pack=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
-       1,--depth) usage;;
-       *,--depth)
+       --depth)
                shift
-               depth="--depth=$1";;
-       *,--)
+               depth="--depth=$1" ;;
+       --)
                shift
                break ;;
-       *,-*) usage ;;
-       *) break ;;
+       *)
+               usage ;;
        esac
-do
        shift
 done
 
index 959c4d68e7bbb501dee1778a33d45eaf09b4bf2d..485339754ca3567c86b824af656700654c68e173 100755 (executable)
@@ -5,6 +5,7 @@
 
 USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
index ffcc408ee5217d7a8f6179a0404ffe387e0dab0f..c9f515d0ee0f36fc44f667f17674462ced7c2c9e 100755 (executable)
@@ -92,6 +92,7 @@ USAGE="[--env-filter <command>] [--tree-filter <command>] \
 [--original <namespace>] [-d <directory>] [-f | --force] \
 [<rev-list options>...]"
 
+OPTIONS_SPEC=
 . git-sh-setup
 
 git diff-files --quiet &&
index ada1180528b08607858efbcce9b2afc6d1b0e061..8503ae40309e6c8b1547289c9950d99f4bf736b5 100755 (executable)
@@ -2,9 +2,21 @@
 #
 # Copyright (c) 2006 Eric Wong
 #
-USAGE='[--start] [--stop] [--restart]
-  [--local] [--httpd=<httpd>] [--port=<port>] [--browser=<browser>]
-  [--module-path=<path> (for Apache2 only)]'
+
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-instaweb [options] (--start | --stop | --restart)
+--
+l,local        only bind on 127.0.0.1
+p,port=        the port to bind to
+d,httpd=       the command to launch
+b,browser=     the browser to launch
+m,module-path= the module path (only needed for apache2)
+ Action
+stop           stop the web server
+start          start the web server
+restart        restart the web server
+"
 
 . git-sh-setup
 
@@ -78,52 +90,26 @@ do
                start_httpd
                exit 0
                ;;
-       --local|-l)
+       -l|--local)
                local=true
                ;;
-       -d|--httpd|--httpd=*)
-               case "$#,$1" in
-               *,*=*)
-                       httpd=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       httpd="$2"
-                       shift ;;
-               esac
+       -d|--httpd)
+               shift
+               httpd="$1"
+               ;;
+       -b|--browser)
+               shift
+               browser="$1"
                ;;
-       -b|--browser|--browser=*)
-               case "$#,$1" in
-               *,*=*)
-                       browser=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       browser="$2"
-                       shift ;;
-               esac
+       -p|--port)
+               shift
+               port="$1"
                ;;
-       -p|--port|--port=*)
-               case "$#,$1" in
-               *,*=*)
-                       port=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       port="$2"
-                       shift ;;
-               esac
+       -m|--module-path)
+               shift
+               module_path="$1"
                ;;
-       -m|--module-path=*|--module-path)
-               case "$#,$1" in
-               *,*=*)
-                       module_path=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       module_path="$2"
-                       shift ;;
-               esac
+       --)
                ;;
        *)
                usage
index f2ec5d147a56136b8c3aff8b693912a7c792da63..9cedaf80ceac1d4100adf3cfb152c76c7f945e4d 100755 (executable)
@@ -2,6 +2,7 @@
 
 USAGE=''
 SUBDIRECTORY_OK='Yes'
+OPTIONS_SPEC=
 . git-sh-setup
 
 echo "WARNING: '$0' is deprecated in favor of 'git fsck --lost-found'" >&2
index b9f05192d1122df13f134b361887060ea042180c..1c123a37e6941b6727c6101bb29cbc485a380c20 100755 (executable)
@@ -3,7 +3,19 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-USAGE='[-n] [--summary] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s <strategy>] [-m=<merge-message>] <commit>+'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-merge [options] <remote>...
+git-merge [options] <msg> HEAD <remote>
+--
+summary              show a diffstat at the end of the merge
+n,no-summary         don't show a diffstat at the end of the merge
+squash               create a single commit instead of doing a merge
+commit               perform a commit if the merge sucesses (default)
+ff                   allow fast forward (default)
+s,strategy=          merge strategy to use
+m,message=           message to be used for the merge commit (if any)
+"
 
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
@@ -132,72 +144,47 @@ merge_name () {
        fi
 }
 
-parse_option () {
-       case "$1" in
-       -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
-               --no-summa|--no-summar|--no-summary)
-               show_diffstat=false ;;
-       --summary)
-               show_diffstat=t ;;
-       --sq|--squ|--squa|--squas|--squash)
-               allow_fast_forward=t squash=t no_commit=t ;;
-       --no-sq|--no-squ|--no-squa|--no-squas|--no-squash)
-               allow_fast_forward=t squash= no_commit= ;;
-       --c|--co|--com|--comm|--commi|--commit)
-               allow_fast_forward=t squash= no_commit= ;;
-       --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
-               allow_fast_forward=t squash= no_commit=t ;;
-       --ff)
-               allow_fast_forward=t squash= no_commit= ;;
-       --no-ff)
-               allow_fast_forward=false squash= no_commit= ;;
-       -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
-               --strateg=*|--strategy=*|\
-       -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
-               case "$#,$1" in
-               *,*=*)
-                       strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       strategy="$2"
-                       shift ;;
-               esac
-               case " $all_strategies " in
-               *" $strategy "*)
-                       use_strategies="$use_strategies$strategy " ;;
-               *)
-                       die "available strategies are: $all_strategies" ;;
-               esac
-               ;;
-       -m=*|--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-               merge_msg=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-               have_message=t
-               ;;
-       -m|--m|--me|--mes|--mess|--messa|--messag|--message)
-               shift
-               case "$#" in
-               1)      usage ;;
-               esac
-               merge_msg="$1"
-               have_message=t
-               ;;
-       -*)     usage ;;
-       *)      return 1 ;;
-       esac
-       shift
-       args_left=$#
-}
-
 parse_config () {
-       while test $# -gt 0
-       do
-               parse_option "$@" || usage
-               while test $args_left -lt $#
-               do
+       while test $# != 0; do
+               case "$1" in
+               -n|--no-summary)
+                       show_diffstat=false ;;
+               --summary)
+                       show_diffstat=t ;;
+               --squash)
+                       allow_fast_forward=t squash=t no_commit=t ;;
+               --no-squash)
+                       allow_fast_forward=t squash= no_commit= ;;
+               --commit)
+                       allow_fast_forward=t squash= no_commit= ;;
+               --no-commit)
+                       allow_fast_forward=t squash= no_commit=t ;;
+               --ff)
+                       allow_fast_forward=t squash= no_commit= ;;
+               --no-ff)
+                       allow_fast_forward=false squash= no_commit= ;;
+               -s|--strategy)
+                       shift
+                       case " $all_strategies " in
+                       *" $1 "*)
+                               use_strategies="$use_strategies$1 " ;;
+                       *)
+                               die "available strategies are: $all_strategies" ;;
+                       esac
+                       ;;
+               -m|--message)
                        shift
-               done
+                       merge_msg="$1"
+                       have_message=t
+                       ;;
+               --)
+                       shift
+                       break ;;
+               *)      usage ;;
+               esac
+               shift
        done
+       args_left=$#
 }
 
 test $# != 0 || usage
@@ -209,17 +196,12 @@ then
        mergeopts=$(git config "branch.${branch#refs/heads/}.mergeoptions")
        if test -n "$mergeopts"
        then
-               parse_config $mergeopts
+               parse_config $mergeopts --
        fi
 fi
 
-while parse_option "$@"
-do
-       while test $args_left -lt $#
-       do
-               shift
-       done
-done
+parse_config "$@"
+while test $args_left -lt $#; do shift; done
 
 if test -z "$show_diffstat"; then
     test "$(git config --bool merge.diffstat)" = false && show_diffstat=false
index a68b40386bde1c47c33a19514ec3a22db7fb0e4b..5587c5ecea0f6a97f2715636890c9e2f89845d52 100755 (executable)
@@ -10,6 +10,7 @@
 
 USAGE='[--tool=tool] [file to merge] ...'
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 prefix=$(git rev-parse --show-prefix)
index 75ec011969f7cd84979911b917b886696a077c5e..30fdc57310897207f2e931396d184e94b48ad2ef 100755 (executable)
@@ -7,6 +7,7 @@
 USAGE='[-n | --no-summary] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
 LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 set_reflog_action "pull $*"
 require_work_tree
index 880c81d121bfb9555c729bc299f8ae8baf1db32c..6b0c4d2f279cf9e567e8c317c21e59d352ce3ff6 100755 (executable)
@@ -1,5 +1,12 @@
 #!/bin/sh
-USAGE='--dry-run --author <author> --patches </path/to/quilt/patch/directory>'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-quiltimport [options]
+--
+n,dry-run     dry run
+author=       author name and email address for patches without any
+patches=      path to the quilt series and patches
+"
 SUBDIRECTORY_ON=Yes
 . git-sh-setup
 
@@ -8,39 +15,25 @@ quilt_author=""
 while test $# != 0
 do
        case "$1" in
-       --au=*|--aut=*|--auth=*|--autho=*|--author=*)
-               quilt_author=$(expr "z$1" : 'z-[^=]*\(.*\)')
-               shift
-               ;;
-
-       --au|--aut|--auth|--autho|--author)
-               case "$#" in 1) usage ;; esac
+       --author)
                shift
                quilt_author="$1"
-               shift
                ;;
-
-       --dry-run)
-               shift
+       -n|--dry-run)
                dry_run=1
                ;;
-
-       --pa=*|--pat=*|--patc=*|--patch=*|--patche=*|--patches=*)
-               QUILT_PATCHES=$(expr "z$1" : 'z-[^=]*\(.*\)')
-               shift
-               ;;
-
-       --pa|--pat|--patc|--patch|--patche|--patches)
-               case "$#" in 1) usage ;; esac
+       --patches)
                shift
                QUILT_PATCHES="$1"
-               shift
                ;;
-
+       --)
+               shift
+               break;;
        *)
-               break
+               usage
                ;;
        esac
+       shift
 done
 
 # Quilt Author
index 51063776d2540ed4ad6537e3578916b40d46c81a..66c80d4e16e3217b93b9de12a4b02d107a2eeb71 100755 (executable)
@@ -13,6 +13,7 @@
 USAGE='(--continue | --abort | --skip | [--preserve-merges] [--verbose]
        [--onto <branch>] <upstream> [<branch>])'
 
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
index c059749bbd5bc1e5bf4103c09b4935c46c965431..df5fd65d56bde3ed046c9ed40e62e8a17ede2e8e 100755 (executable)
@@ -29,6 +29,7 @@ Example:       git-rebase master~1 topic
 '
 
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 set_reflog_action rebase
 require_work_tree
index 7220635c96a75a17634297b33bac8322647b8270..e18eb3f5dcf42abfbd125594877ececf92c3d9b6 100755 (executable)
@@ -3,7 +3,22 @@
 # Copyright (c) 2005 Linus Torvalds
 #
 
-USAGE='[-a|-A] [-d] [-f] [-l] [-n] [-q] [--max-pack-size=N] [--window=N] [--window-memory=N] [--depth=N]'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-repack [options]
+--
+a               pack everything in a single pack
+A               same as -a, and keep unreachable objects too
+d               remove redundant packs, and run git-prune-packed
+f               pass --no-reuse-delta to git-pack-objects
+q,quiet         be quiet
+l               pass --local to git-pack-objects
+ Packing constraints
+window=         size of the window used for delta compression
+window-memory=  same as the above, but limit memory size instead of entries count
+depth=          limits the maximum delta depth
+max-pack-size=  maximum size of each packfile
+"
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
@@ -20,10 +35,9 @@ do
        -q)     quiet=-q ;;
        -f)     no_reuse=--no-reuse-object ;;
        -l)     local=--local ;;
-       --max-pack-size=*) extra="$extra $1" ;;
-       --window=*) extra="$extra $1" ;;
-       --window-memory=*) extra="$extra $1" ;;
-       --depth=*) extra="$extra $1" ;;
+       --max-pack-size|--window|--window-memory|--depth)
+               extra="$extra $1=$2"; shift ;;
+       --) shift; break;;
        *)      usage ;;
        esac
        shift
index 95ad66630f39effead53598a650dec0ab7b90289..068f5e0fc7308db601141bc3e70475ec2145ef67 100755 (executable)
@@ -8,6 +8,7 @@ USAGE='<commit> <url> [<head>]'
 LONG_USAGE='Summarizes the changes since <commit> to the standard output,
 and includes <url> in the message generated.'
 SUBDIRECTORY_OK='Yes'
+OPTIONS_SPEC=
 . git-sh-setup
 . git-parse-remote
 
index 86d7d4c4e742c80e936d5f1c9f2037327eba7287..5aa62dda15d1c24d0b01845ded4c8bc15e98bf8a 100755 (executable)
@@ -16,9 +16,40 @@ die() {
        exit 1
 }
 
-usage() {
-       die "Usage: $0 $USAGE"
-}
+if test -n "$OPTIONS_SPEC"; then
+       usage() {
+               exec "$0" -h
+       }
+
+       parseopt_extra=
+       [ -n "$OPTIONS_KEEPDASHDASH" ] &&
+               parseopt_extra="--keep-dashdash"
+
+       eval "$(
+               echo "$OPTIONS_SPEC" |
+                       git rev-parse --parseopt $parseopt_extra -- "$@" ||
+               echo exit $?
+       )"
+else
+       usage() {
+               die "Usage: $0 $USAGE"
+       }
+
+       if [ -z "$LONG_USAGE" ]
+       then
+               LONG_USAGE="Usage: $0 $USAGE"
+       else
+               LONG_USAGE="Usage: $0 $USAGE
+
+$LONG_USAGE"
+       fi
+
+       case "$1" in
+               -h|--h|--he|--hel|--help)
+               echo "$LONG_USAGE"
+               exit
+       esac
+fi
 
 set_reflog_action() {
        if [ -z "${GIT_REFLOG_ACTION:+set}" ]
@@ -91,21 +122,6 @@ get_author_ident_from_commit () {
        LANG=C LC_ALL=C sed -ne "$pick_author_script"
 }
 
-if [ -z "$LONG_USAGE" ]
-then
-       LONG_USAGE="Usage: $0 $USAGE"
-else
-       LONG_USAGE="Usage: $0 $USAGE
-
-$LONG_USAGE"
-fi
-
-case "$1" in
-       -h|--h|--he|--hel|--help)
-       echo "$LONG_USAGE"
-       exit
-esac
-
 # Make sure we are in a valid repository of a vintage we understand.
 if [ -z "$SUBDIRECTORY_OK" ]
 then
index 1c8b7f92591f87b2d32b51cca6173921c5e041b2..534eb168abf8b0b8ae5c2195bf85b66d9cb6b21e 100755 (executable)
@@ -4,6 +4,7 @@
 USAGE='[ | list | show | apply | clear]'
 
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 cd_to_toplevel
index 5af28ecd58de8c46f194280887ef9c27c784e606..82ac28fa27dc41b821905f1a83155994d56c4f3b 100755 (executable)
@@ -5,6 +5,7 @@
 # Copyright (c) 2007 Lars Hjemli
 
 USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]'
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
diff --git a/git.c b/git.c
index 4a250f7e8b84f2334c84daaf93baa0fe1f0ca344..7604319b5a9e8c12b2f00b4d5e6480445e02daa6 100644 (file)
--- a/git.c
+++ b/git.c
@@ -338,7 +338,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "rerere", cmd_rerere, RUN_SETUP },
                { "reset", cmd_reset, RUN_SETUP },
                { "rev-list", cmd_rev_list, RUN_SETUP },
-               { "rev-parse", cmd_rev_parse, RUN_SETUP },
+               { "rev-parse", cmd_rev_parse },
                { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
                { "rm", cmd_rm, RUN_SETUP },
                { "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },