execv_dashed_external: wait for child on signal death
[gitweb.git] / builtin / rev-parse.c
index 7a4f2c0b0ccedf958b78b2bdda217bfb269c6b23..cfb0f1510c59674abe68fb67ff45142b5c92ac89 100644 (file)
@@ -298,14 +298,30 @@ static int try_parent_shorthands(const char *arg)
        unsigned char sha1[20];
        struct commit *commit;
        struct commit_list *parents;
-       int parents_only;
-
-       if ((dotdot = strstr(arg, "^!")))
-               parents_only = 0;
-       else if ((dotdot = strstr(arg, "^@")))
-               parents_only = 1;
-
-       if (!dotdot || dotdot[2])
+       int parent_number;
+       int include_rev = 0;
+       int include_parents = 0;
+       int exclude_parent = 0;
+
+       if ((dotdot = strstr(arg, "^!"))) {
+               include_rev = 1;
+               if (dotdot[2])
+                       return 0;
+       } else if ((dotdot = strstr(arg, "^@"))) {
+               include_parents = 1;
+               if (dotdot[2])
+                       return 0;
+       } else if ((dotdot = strstr(arg, "^-"))) {
+               include_rev = 1;
+               exclude_parent = 1;
+
+               if (dotdot[2]) {
+                       char *end;
+                       exclude_parent = strtoul(dotdot + 2, &end, 10);
+                       if (*end != '\0' || !exclude_parent)
+                               return 0;
+               }
+       } else
                return 0;
 
        *dotdot = 0;
@@ -314,12 +330,24 @@ static int try_parent_shorthands(const char *arg)
                return 0;
        }
 
-       if (!parents_only)
-               show_rev(NORMAL, sha1, arg);
        commit = lookup_commit_reference(sha1);
-       for (parents = commit->parents; parents; parents = parents->next)
-               show_rev(parents_only ? NORMAL : REVERSED,
-                               parents->item->object.oid.hash, arg);
+       if (exclude_parent &&
+           exclude_parent > commit_list_count(commit->parents)) {
+               *dotdot = '^';
+               return 0;
+       }
+
+       if (include_rev)
+               show_rev(NORMAL, sha1, arg);
+       for (parents = commit->parents, parent_number = 1;
+            parents;
+            parents = parents->next, parent_number++) {
+               if (exclude_parent && parent_number != exclude_parent)
+                       continue;
+
+               show_rev(include_parents ? NORMAL : REVERSED,
+                        parents->item->object.oid.hash, arg);
+       }
 
        *dotdot = '^';
        return 1;
@@ -383,7 +411,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
 
        /* get the usage up to the first line with a -- on it */
        for (;;) {
-               if (strbuf_getline(&sb, stdin, '\n') == EOF)
+               if (strbuf_getline(&sb, stdin) == EOF)
                        die("premature end of input");
                ALLOC_GROW(usage, unb + 1, usz);
                if (!strcmp("--", sb.buf)) {
@@ -396,7 +424,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
        }
 
        /* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
-       while (strbuf_getline(&sb, stdin, '\n') != EOF) {
+       while (strbuf_getline(&sb, stdin) != EOF) {
                const char *s;
                const char *help;
                struct option *o;
@@ -469,7 +497,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
                        (stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
                        PARSE_OPT_SHELL_EVAL);
 
-       strbuf_addf(&parsed, " --");
+       strbuf_addstr(&parsed, " --");
        sq_quote_argv(&parsed, argv, 0);
        puts(parsed.buf);
        return 0;
@@ -505,6 +533,7 @@ N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 {
        int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
+       int did_repo_setup = 0;
        int has_dashdash = 0;
        int output_prefix = 0;
        unsigned char sha1[20];
@@ -528,11 +557,40 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                }
        }
 
-       prefix = setup_git_directory();
-       git_config(git_default_config, NULL);
+       /* No options; just report on whether we're in a git repo or not. */
+       if (argc == 1) {
+               setup_git_directory();
+               git_config(git_default_config, NULL);
+               return 0;
+       }
+
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
+               if (!strcmp(arg, "--local-env-vars")) {
+                       int i;
+                       for (i = 0; local_repo_env[i]; i++)
+                               printf("%s\n", local_repo_env[i]);
+                       continue;
+               }
+               if (!strcmp(arg, "--resolve-git-dir")) {
+                       const char *gitdir = argv[++i];
+                       if (!gitdir)
+                               die("--resolve-git-dir requires an argument");
+                       gitdir = resolve_gitdir(gitdir);
+                       if (!gitdir)
+                               die("not a gitdir '%s'", argv[i]);
+                       puts(gitdir);
+                       continue;
+               }
+
+               /* The rest of the options require a git repository. */
+               if (!did_repo_setup) {
+                       prefix = setup_git_directory();
+                       git_config(git_default_config, NULL);
+                       did_repo_setup = 1;
+               }
+
                if (!strcmp(arg, "--git-path")) {
                        if (!argv[i + 1])
                                die("--git-path requires an argument");
@@ -613,8 +671,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                filter &= ~(DO_FLAGS|DO_NOREV);
                                verify = 1;
                                abbrev = DEFAULT_ABBREV;
-                               if (arg[7] == '=')
-                                       abbrev = strtoul(arg + 8, NULL, 10);
+                               if (!arg[7])
+                                       continue;
+                               abbrev = strtoul(arg + 8, NULL, 10);
                                if (abbrev < MINIMUM_ABBREV)
                                        abbrev = MINIMUM_ABBREV;
                                else if (40 <= abbrev)
@@ -706,12 +765,6 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                add_ref_exclusion(&ref_excludes, arg + 10);
                                continue;
                        }
-                       if (!strcmp(arg, "--local-env-vars")) {
-                               int i;
-                               for (i = 0; local_repo_env[i]; i++)
-                                       printf("%s\n", local_repo_env[i]);
-                               continue;
-                       }
                        if (!strcmp(arg, "--show-toplevel")) {
                                const char *work_tree = get_git_work_tree();
                                if (work_tree)
@@ -767,16 +820,6 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                puts(prefix_filename(pfx, strlen(pfx), get_git_common_dir()));
                                continue;
                        }
-                       if (!strcmp(arg, "--resolve-git-dir")) {
-                               const char *gitdir = argv[++i];
-                               if (!gitdir)
-                                       die("--resolve-git-dir requires an argument");
-                               gitdir = resolve_gitdir(gitdir);
-                               if (!gitdir)
-                                       die("not a gitdir '%s'", argv[i]);
-                               puts(gitdir);
-                               continue;
-                       }
                        if (!strcmp(arg, "--is-inside-git-dir")) {
                                printf("%s\n", is_inside_git_dir() ? "true"
                                                : "false");