Sync with 2.17.6
[git] / builtin / rev-parse.c
1 /*
2  * rev-parse.c
3  *
4  * Copyright (C) Linus Torvalds, 2005
5  */
6 #include "cache.h"
7 #include "config.h"
8 #include "commit.h"
9 #include "refs.h"
10 #include "quote.h"
11 #include "builtin.h"
12 #include "parse-options.h"
13 #include "diff.h"
14 #include "revision.h"
15 #include "split-index.h"
16 #include "submodule.h"
17
18 #define DO_REVS         1
19 #define DO_NOREV        2
20 #define DO_FLAGS        4
21 #define DO_NONFLAGS     8
22 static int filter = ~0;
23
24 static const char *def;
25
26 #define NORMAL 0
27 #define REVERSED 1
28 static int show_type = NORMAL;
29
30 #define SHOW_SYMBOLIC_ASIS 1
31 #define SHOW_SYMBOLIC_FULL 2
32 static int symbolic;
33 static int abbrev;
34 static int abbrev_ref;
35 static int abbrev_ref_strict;
36 static int output_sq;
37
38 static int stuck_long;
39 static struct string_list *ref_excludes;
40
41 /*
42  * Some arguments are relevant "revision" arguments,
43  * others are about output format or other details.
44  * This sorts it all out.
45  */
46 static int is_rev_argument(const char *arg)
47 {
48         static const char *rev_args[] = {
49                 "--all",
50                 "--bisect",
51                 "--dense",
52                 "--branches=",
53                 "--branches",
54                 "--header",
55                 "--ignore-missing",
56                 "--max-age=",
57                 "--max-count=",
58                 "--min-age=",
59                 "--no-merges",
60                 "--min-parents=",
61                 "--no-min-parents",
62                 "--max-parents=",
63                 "--no-max-parents",
64                 "--objects",
65                 "--objects-edge",
66                 "--parents",
67                 "--pretty",
68                 "--remotes=",
69                 "--remotes",
70                 "--glob=",
71                 "--sparse",
72                 "--tags=",
73                 "--tags",
74                 "--topo-order",
75                 "--date-order",
76                 "--unpacked",
77                 NULL
78         };
79         const char **p = rev_args;
80
81         /* accept -<digit>, like traditional "head" */
82         if ((*arg == '-') && isdigit(arg[1]))
83                 return 1;
84
85         for (;;) {
86                 const char *str = *p++;
87                 int len;
88                 if (!str)
89                         return 0;
90                 len = strlen(str);
91                 if (!strcmp(arg, str) ||
92                     (str[len-1] == '=' && !strncmp(arg, str, len)))
93                         return 1;
94         }
95 }
96
97 /* Output argument as a string, either SQ or normal */
98 static void show(const char *arg)
99 {
100         if (output_sq) {
101                 int sq = '\'', ch;
102
103                 putchar(sq);
104                 while ((ch = *arg++)) {
105                         if (ch == sq)
106                                 fputs("'\\'", stdout);
107                         putchar(ch);
108                 }
109                 putchar(sq);
110                 putchar(' ');
111         }
112         else
113                 puts(arg);
114 }
115
116 /* Like show(), but with a negation prefix according to type */
117 static void show_with_type(int type, const char *arg)
118 {
119         if (type != show_type)
120                 putchar('^');
121         show(arg);
122 }
123
124 /* Output a revision, only if filter allows it */
125 static void show_rev(int type, const struct object_id *oid, const char *name)
126 {
127         if (!(filter & DO_REVS))
128                 return;
129         def = NULL;
130
131         if ((symbolic || abbrev_ref) && name) {
132                 if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
133                         struct object_id discard;
134                         char *full;
135
136                         switch (dwim_ref(name, strlen(name), &discard, &full)) {
137                         case 0:
138                                 /*
139                                  * Not found -- not a ref.  We could
140                                  * emit "name" here, but symbolic-full
141                                  * users are interested in finding the
142                                  * refs spelled in full, and they would
143                                  * need to filter non-refs if we did so.
144                                  */
145                                 break;
146                         case 1: /* happy */
147                                 if (abbrev_ref)
148                                         full = shorten_unambiguous_ref(full,
149                                                 abbrev_ref_strict);
150                                 show_with_type(type, full);
151                                 break;
152                         default: /* ambiguous */
153                                 error("refname '%s' is ambiguous", name);
154                                 break;
155                         }
156                         free(full);
157                 } else {
158                         show_with_type(type, name);
159                 }
160         }
161         else if (abbrev)
162                 show_with_type(type, find_unique_abbrev(oid, abbrev));
163         else
164                 show_with_type(type, oid_to_hex(oid));
165 }
166
167 /* Output a flag, only if filter allows it. */
168 static int show_flag(const char *arg)
169 {
170         if (!(filter & DO_FLAGS))
171                 return 0;
172         if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
173                 show(arg);
174                 return 1;
175         }
176         return 0;
177 }
178
179 static int show_default(void)
180 {
181         const char *s = def;
182
183         if (s) {
184                 struct object_id oid;
185
186                 def = NULL;
187                 if (!get_oid(s, &oid)) {
188                         show_rev(NORMAL, &oid, s);
189                         return 1;
190                 }
191         }
192         return 0;
193 }
194
195 static int show_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
196 {
197         if (ref_excluded(ref_excludes, refname))
198                 return 0;
199         show_rev(NORMAL, oid, refname);
200         return 0;
201 }
202
203 static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
204 {
205         show_rev(REVERSED, oid, refname);
206         return 0;
207 }
208
209 static int show_abbrev(const struct object_id *oid, void *cb_data)
210 {
211         show_rev(NORMAL, oid, NULL);
212         return 0;
213 }
214
215 static void show_datestring(const char *flag, const char *datestr)
216 {
217         char *buffer;
218
219         /* date handling requires both flags and revs */
220         if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
221                 return;
222         buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
223         show(buffer);
224         free(buffer);
225 }
226
227 static int show_file(const char *arg, int output_prefix)
228 {
229         show_default();
230         if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
231                 if (output_prefix) {
232                         const char *prefix = startup_info->prefix;
233                         char *fname = prefix_filename(prefix, arg);
234                         show(fname);
235                         free(fname);
236                 } else
237                         show(arg);
238                 return 1;
239         }
240         return 0;
241 }
242
243 static int try_difference(const char *arg)
244 {
245         char *dotdot;
246         struct object_id start_oid;
247         struct object_id end_oid;
248         const char *end;
249         const char *start;
250         int symmetric;
251         static const char head_by_default[] = "HEAD";
252
253         if (!(dotdot = strstr(arg, "..")))
254                 return 0;
255         end = dotdot + 2;
256         start = arg;
257         symmetric = (*end == '.');
258
259         *dotdot = 0;
260         end += symmetric;
261
262         if (!*end)
263                 end = head_by_default;
264         if (dotdot == arg)
265                 start = head_by_default;
266
267         if (start == head_by_default && end == head_by_default &&
268             !symmetric) {
269                 /*
270                  * Just ".."?  That is not a range but the
271                  * pathspec for the parent directory.
272                  */
273                 *dotdot = '.';
274                 return 0;
275         }
276
277         if (!get_oid_committish(start, &start_oid) && !get_oid_committish(end, &end_oid)) {
278                 show_rev(NORMAL, &end_oid, end);
279                 show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
280                 if (symmetric) {
281                         struct commit_list *exclude;
282                         struct commit *a, *b;
283                         a = lookup_commit_reference(&start_oid);
284                         b = lookup_commit_reference(&end_oid);
285                         if (!a || !b) {
286                                 *dotdot = '.';
287                                 return 0;
288                         }
289                         exclude = get_merge_bases(a, b);
290                         while (exclude) {
291                                 struct commit *commit = pop_commit(&exclude);
292                                 show_rev(REVERSED, &commit->object.oid, NULL);
293                         }
294                 }
295                 *dotdot = '.';
296                 return 1;
297         }
298         *dotdot = '.';
299         return 0;
300 }
301
302 static int try_parent_shorthands(const char *arg)
303 {
304         char *dotdot;
305         struct object_id oid;
306         struct commit *commit;
307         struct commit_list *parents;
308         int parent_number;
309         int include_rev = 0;
310         int include_parents = 0;
311         int exclude_parent = 0;
312
313         if ((dotdot = strstr(arg, "^!"))) {
314                 include_rev = 1;
315                 if (dotdot[2])
316                         return 0;
317         } else if ((dotdot = strstr(arg, "^@"))) {
318                 include_parents = 1;
319                 if (dotdot[2])
320                         return 0;
321         } else if ((dotdot = strstr(arg, "^-"))) {
322                 include_rev = 1;
323                 exclude_parent = 1;
324
325                 if (dotdot[2]) {
326                         char *end;
327                         exclude_parent = strtoul(dotdot + 2, &end, 10);
328                         if (*end != '\0' || !exclude_parent)
329                                 return 0;
330                 }
331         } else
332                 return 0;
333
334         *dotdot = 0;
335         if (get_oid_committish(arg, &oid) ||
336             !(commit = lookup_commit_reference(&oid))) {
337                 *dotdot = '^';
338                 return 0;
339         }
340
341         if (exclude_parent &&
342             exclude_parent > commit_list_count(commit->parents)) {
343                 *dotdot = '^';
344                 return 0;
345         }
346
347         if (include_rev)
348                 show_rev(NORMAL, &oid, arg);
349         for (parents = commit->parents, parent_number = 1;
350              parents;
351              parents = parents->next, parent_number++) {
352                 char *name = NULL;
353
354                 if (exclude_parent && parent_number != exclude_parent)
355                         continue;
356
357                 if (symbolic)
358                         name = xstrfmt("%s^%d", arg, parent_number);
359                 show_rev(include_parents ? NORMAL : REVERSED,
360                          &parents->item->object.oid, name);
361                 free(name);
362         }
363
364         *dotdot = '^';
365         return 1;
366 }
367
368 static int parseopt_dump(const struct option *o, const char *arg, int unset)
369 {
370         struct strbuf *parsed = o->value;
371         if (unset)
372                 strbuf_addf(parsed, " --no-%s", o->long_name);
373         else if (o->short_name && (o->long_name == NULL || !stuck_long))
374                 strbuf_addf(parsed, " -%c", o->short_name);
375         else
376                 strbuf_addf(parsed, " --%s", o->long_name);
377         if (arg) {
378                 if (!stuck_long)
379                         strbuf_addch(parsed, ' ');
380                 else if (o->long_name)
381                         strbuf_addch(parsed, '=');
382                 sq_quote_buf(parsed, arg);
383         }
384         return 0;
385 }
386
387 static const char *skipspaces(const char *s)
388 {
389         while (isspace(*s))
390                 s++;
391         return s;
392 }
393
394 static char *findspace(const char *s)
395 {
396         for (; *s; s++)
397                 if (isspace(*s))
398                         return (char*)s;
399         return NULL;
400 }
401
402 static int cmd_parseopt(int argc, const char **argv, const char *prefix)
403 {
404         static int keep_dashdash = 0, stop_at_non_option = 0;
405         static char const * const parseopt_usage[] = {
406                 N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
407                 NULL
408         };
409         static struct option parseopt_opts[] = {
410                 OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
411                                         N_("keep the `--` passed as an arg")),
412                 OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
413                                         N_("stop parsing after the "
414                                            "first non-option argument")),
415                 OPT_BOOL(0, "stuck-long", &stuck_long,
416                                         N_("output in stuck long form")),
417                 OPT_END(),
418         };
419         static const char * const flag_chars = "*=?!";
420
421         struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
422         const char **usage = NULL;
423         struct option *opts = NULL;
424         int onb = 0, osz = 0, unb = 0, usz = 0;
425
426         strbuf_addstr(&parsed, "set --");
427         argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
428                              PARSE_OPT_KEEP_DASHDASH);
429         if (argc < 1 || strcmp(argv[0], "--"))
430                 usage_with_options(parseopt_usage, parseopt_opts);
431
432         /* get the usage up to the first line with a -- on it */
433         for (;;) {
434                 if (strbuf_getline(&sb, stdin) == EOF)
435                         die("premature end of input");
436                 ALLOC_GROW(usage, unb + 1, usz);
437                 if (!strcmp("--", sb.buf)) {
438                         if (unb < 1)
439                                 die("no usage string given before the `--' separator");
440                         usage[unb] = NULL;
441                         break;
442                 }
443                 usage[unb++] = strbuf_detach(&sb, NULL);
444         }
445
446         /* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
447         while (strbuf_getline(&sb, stdin) != EOF) {
448                 const char *s;
449                 char *help;
450                 struct option *o;
451
452                 if (!sb.len)
453                         continue;
454
455                 ALLOC_GROW(opts, onb + 1, osz);
456                 memset(opts + onb, 0, sizeof(opts[onb]));
457
458                 o = &opts[onb++];
459                 help = findspace(sb.buf);
460                 if (!help || sb.buf == help) {
461                         o->type = OPTION_GROUP;
462                         o->help = xstrdup(skipspaces(sb.buf));
463                         continue;
464                 }
465
466                 *help = '\0';
467
468                 o->type = OPTION_CALLBACK;
469                 o->help = xstrdup(skipspaces(help+1));
470                 o->value = &parsed;
471                 o->flags = PARSE_OPT_NOARG;
472                 o->callback = &parseopt_dump;
473
474                 /* name(s) */
475                 s = strpbrk(sb.buf, flag_chars);
476                 if (s == NULL)
477                         s = help;
478
479                 if (s - sb.buf == 1) /* short option only */
480                         o->short_name = *sb.buf;
481                 else if (sb.buf[1] != ',') /* long option only */
482                         o->long_name = xmemdupz(sb.buf, s - sb.buf);
483                 else {
484                         o->short_name = *sb.buf;
485                         o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
486                 }
487
488                 /* flags */
489                 while (s < help) {
490                         switch (*s++) {
491                         case '=':
492                                 o->flags &= ~PARSE_OPT_NOARG;
493                                 continue;
494                         case '?':
495                                 o->flags &= ~PARSE_OPT_NOARG;
496                                 o->flags |= PARSE_OPT_OPTARG;
497                                 continue;
498                         case '!':
499                                 o->flags |= PARSE_OPT_NONEG;
500                                 continue;
501                         case '*':
502                                 o->flags |= PARSE_OPT_HIDDEN;
503                                 continue;
504                         }
505                         s--;
506                         break;
507                 }
508
509                 if (s < help)
510                         o->argh = xmemdupz(s, help - s);
511         }
512         strbuf_release(&sb);
513
514         /* put an OPT_END() */
515         ALLOC_GROW(opts, onb + 1, osz);
516         memset(opts + onb, 0, sizeof(opts[onb]));
517         argc = parse_options(argc, argv, prefix, opts, usage,
518                         (keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
519                         (stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
520                         PARSE_OPT_SHELL_EVAL);
521
522         strbuf_addstr(&parsed, " --");
523         sq_quote_argv(&parsed, argv);
524         puts(parsed.buf);
525         return 0;
526 }
527
528 static int cmd_sq_quote(int argc, const char **argv)
529 {
530         struct strbuf buf = STRBUF_INIT;
531
532         if (argc)
533                 sq_quote_argv(&buf, argv);
534         printf("%s\n", buf.buf);
535         strbuf_release(&buf);
536
537         return 0;
538 }
539
540 static void die_no_single_rev(int quiet)
541 {
542         if (quiet)
543                 exit(1);
544         else
545                 die("Needed a single revision");
546 }
547
548 static const char builtin_rev_parse_usage[] =
549 N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
550    "   or: git rev-parse --sq-quote [<arg>...]\n"
551    "   or: git rev-parse [<options>] [<arg>...]\n"
552    "\n"
553    "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
554
555 /*
556  * Parse "opt" or "opt=<value>", setting value respectively to either
557  * NULL or the string after "=".
558  */
559 static int opt_with_value(const char *arg, const char *opt, const char **value)
560 {
561         if (skip_prefix(arg, opt, &arg)) {
562                 if (!*arg) {
563                         *value = NULL;
564                         return 1;
565                 }
566                 if (*arg++ == '=') {
567                         *value = arg;
568                         return 1;
569                 }
570         }
571         return 0;
572 }
573
574 static void handle_ref_opt(const char *pattern, const char *prefix)
575 {
576         if (pattern)
577                 for_each_glob_ref_in(show_reference, pattern, prefix, NULL);
578         else
579                 for_each_ref_in(prefix, show_reference, NULL);
580         clear_ref_exclusion(&ref_excludes);
581 }
582
583 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
584 {
585         int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
586         int did_repo_setup = 0;
587         int has_dashdash = 0;
588         int output_prefix = 0;
589         struct object_id oid;
590         unsigned int flags = 0;
591         const char *name = NULL;
592         struct object_context unused;
593         struct strbuf buf = STRBUF_INIT;
594
595         if (argc > 1 && !strcmp("--parseopt", argv[1]))
596                 return cmd_parseopt(argc - 1, argv + 1, prefix);
597
598         if (argc > 1 && !strcmp("--sq-quote", argv[1]))
599                 return cmd_sq_quote(argc - 2, argv + 2);
600
601         if (argc > 1 && !strcmp("-h", argv[1]))
602                 usage(builtin_rev_parse_usage);
603
604         for (i = 1; i < argc; i++) {
605                 if (!strcmp(argv[i], "--")) {
606                         has_dashdash = 1;
607                         break;
608                 }
609         }
610
611         /* No options; just report on whether we're in a git repo or not. */
612         if (argc == 1) {
613                 setup_git_directory();
614                 git_config(git_default_config, NULL);
615                 return 0;
616         }
617
618         for (i = 1; i < argc; i++) {
619                 const char *arg = argv[i];
620
621                 if (!strcmp(arg, "--local-env-vars")) {
622                         int i;
623                         for (i = 0; local_repo_env[i]; i++)
624                                 printf("%s\n", local_repo_env[i]);
625                         continue;
626                 }
627                 if (!strcmp(arg, "--resolve-git-dir")) {
628                         const char *gitdir = argv[++i];
629                         if (!gitdir)
630                                 die("--resolve-git-dir requires an argument");
631                         gitdir = resolve_gitdir(gitdir);
632                         if (!gitdir)
633                                 die("not a gitdir '%s'", argv[i]);
634                         puts(gitdir);
635                         continue;
636                 }
637
638                 /* The rest of the options require a git repository. */
639                 if (!did_repo_setup) {
640                         prefix = setup_git_directory();
641                         git_config(git_default_config, NULL);
642                         did_repo_setup = 1;
643                 }
644
645                 if (!strcmp(arg, "--git-path")) {
646                         if (!argv[i + 1])
647                                 die("--git-path requires an argument");
648                         strbuf_reset(&buf);
649                         puts(relative_path(git_path("%s", argv[i + 1]),
650                                            prefix, &buf));
651                         i++;
652                         continue;
653                 }
654                 if (as_is) {
655                         if (show_file(arg, output_prefix) && as_is < 2)
656                                 verify_filename(prefix, arg, 0);
657                         continue;
658                 }
659                 if (!strcmp(arg,"-n")) {
660                         if (++i >= argc)
661                                 die("-n requires an argument");
662                         if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
663                                 show(arg);
664                                 show(argv[i]);
665                         }
666                         continue;
667                 }
668                 if (starts_with(arg, "-n")) {
669                         if ((filter & DO_FLAGS) && (filter & DO_REVS))
670                                 show(arg);
671                         continue;
672                 }
673
674                 if (*arg == '-') {
675                         if (!strcmp(arg, "--")) {
676                                 as_is = 2;
677                                 /* Pass on the "--" if we show anything but files.. */
678                                 if (filter & (DO_FLAGS | DO_REVS))
679                                         show_file(arg, 0);
680                                 continue;
681                         }
682                         if (!strcmp(arg, "--default")) {
683                                 def = argv[++i];
684                                 if (!def)
685                                         die("--default requires an argument");
686                                 continue;
687                         }
688                         if (!strcmp(arg, "--prefix")) {
689                                 prefix = argv[++i];
690                                 if (!prefix)
691                                         die("--prefix requires an argument");
692                                 startup_info->prefix = prefix;
693                                 output_prefix = 1;
694                                 continue;
695                         }
696                         if (!strcmp(arg, "--revs-only")) {
697                                 filter &= ~DO_NOREV;
698                                 continue;
699                         }
700                         if (!strcmp(arg, "--no-revs")) {
701                                 filter &= ~DO_REVS;
702                                 continue;
703                         }
704                         if (!strcmp(arg, "--flags")) {
705                                 filter &= ~DO_NONFLAGS;
706                                 continue;
707                         }
708                         if (!strcmp(arg, "--no-flags")) {
709                                 filter &= ~DO_FLAGS;
710                                 continue;
711                         }
712                         if (!strcmp(arg, "--verify")) {
713                                 filter &= ~(DO_FLAGS|DO_NOREV);
714                                 verify = 1;
715                                 continue;
716                         }
717                         if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
718                                 quiet = 1;
719                                 flags |= GET_OID_QUIETLY;
720                                 continue;
721                         }
722                         if (opt_with_value(arg, "--short", &arg)) {
723                                 filter &= ~(DO_FLAGS|DO_NOREV);
724                                 verify = 1;
725                                 abbrev = DEFAULT_ABBREV;
726                                 if (!arg)
727                                         continue;
728                                 abbrev = strtoul(arg, NULL, 10);
729                                 if (abbrev < MINIMUM_ABBREV)
730                                         abbrev = MINIMUM_ABBREV;
731                                 else if (40 <= abbrev)
732                                         abbrev = 40;
733                                 continue;
734                         }
735                         if (!strcmp(arg, "--sq")) {
736                                 output_sq = 1;
737                                 continue;
738                         }
739                         if (!strcmp(arg, "--not")) {
740                                 show_type ^= REVERSED;
741                                 continue;
742                         }
743                         if (!strcmp(arg, "--symbolic")) {
744                                 symbolic = SHOW_SYMBOLIC_ASIS;
745                                 continue;
746                         }
747                         if (!strcmp(arg, "--symbolic-full-name")) {
748                                 symbolic = SHOW_SYMBOLIC_FULL;
749                                 continue;
750                         }
751                         if (opt_with_value(arg, "--abbrev-ref", &arg)) {
752                                 abbrev_ref = 1;
753                                 abbrev_ref_strict = warn_ambiguous_refs;
754                                 if (arg) {
755                                         if (!strcmp(arg, "strict"))
756                                                 abbrev_ref_strict = 1;
757                                         else if (!strcmp(arg, "loose"))
758                                                 abbrev_ref_strict = 0;
759                                         else
760                                                 die("unknown mode for --abbrev-ref: %s",
761                                                     arg);
762                                 }
763                                 continue;
764                         }
765                         if (!strcmp(arg, "--all")) {
766                                 for_each_ref(show_reference, NULL);
767                                 continue;
768                         }
769                         if (skip_prefix(arg, "--disambiguate=", &arg)) {
770                                 for_each_abbrev(arg, show_abbrev, NULL);
771                                 continue;
772                         }
773                         if (!strcmp(arg, "--bisect")) {
774                                 for_each_fullref_in("refs/bisect/bad", show_reference, NULL, 0);
775                                 for_each_fullref_in("refs/bisect/good", anti_reference, NULL, 0);
776                                 continue;
777                         }
778                         if (opt_with_value(arg, "--branches", &arg)) {
779                                 handle_ref_opt(arg, "refs/heads/");
780                                 continue;
781                         }
782                         if (opt_with_value(arg, "--tags", &arg)) {
783                                 handle_ref_opt(arg, "refs/tags/");
784                                 continue;
785                         }
786                         if (skip_prefix(arg, "--glob=", &arg)) {
787                                 handle_ref_opt(arg, NULL);
788                                 continue;
789                         }
790                         if (opt_with_value(arg, "--remotes", &arg)) {
791                                 handle_ref_opt(arg, "refs/remotes/");
792                                 continue;
793                         }
794                         if (skip_prefix(arg, "--exclude=", &arg)) {
795                                 add_ref_exclusion(&ref_excludes, arg);
796                                 continue;
797                         }
798                         if (!strcmp(arg, "--show-toplevel")) {
799                                 const char *work_tree = get_git_work_tree();
800                                 if (work_tree)
801                                         puts(work_tree);
802                                 continue;
803                         }
804                         if (!strcmp(arg, "--show-superproject-working-tree")) {
805                                 const char *superproject = get_superproject_working_tree();
806                                 if (superproject)
807                                         puts(superproject);
808                                 continue;
809                         }
810                         if (!strcmp(arg, "--show-prefix")) {
811                                 if (prefix)
812                                         puts(prefix);
813                                 else
814                                         putchar('\n');
815                                 continue;
816                         }
817                         if (!strcmp(arg, "--show-cdup")) {
818                                 const char *pfx = prefix;
819                                 if (!is_inside_work_tree()) {
820                                         const char *work_tree =
821                                                 get_git_work_tree();
822                                         if (work_tree)
823                                                 printf("%s\n", work_tree);
824                                         continue;
825                                 }
826                                 while (pfx) {
827                                         pfx = strchr(pfx, '/');
828                                         if (pfx) {
829                                                 pfx++;
830                                                 printf("../");
831                                         }
832                                 }
833                                 putchar('\n');
834                                 continue;
835                         }
836                         if (!strcmp(arg, "--git-dir") ||
837                             !strcmp(arg, "--absolute-git-dir")) {
838                                 const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
839                                 char *cwd;
840                                 int len;
841                                 if (arg[2] == 'g') {    /* --git-dir */
842                                         if (gitdir) {
843                                                 puts(gitdir);
844                                                 continue;
845                                         }
846                                         if (!prefix) {
847                                                 puts(".git");
848                                                 continue;
849                                         }
850                                 } else {                /* --absolute-git-dir */
851                                         if (!gitdir && !prefix)
852                                                 gitdir = ".git";
853                                         if (gitdir) {
854                                                 puts(real_path(gitdir));
855                                                 continue;
856                                         }
857                                 }
858                                 cwd = xgetcwd();
859                                 len = strlen(cwd);
860                                 printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
861                                 free(cwd);
862                                 continue;
863                         }
864                         if (!strcmp(arg, "--git-common-dir")) {
865                                 strbuf_reset(&buf);
866                                 puts(relative_path(get_git_common_dir(),
867                                                    prefix, &buf));
868                                 continue;
869                         }
870                         if (!strcmp(arg, "--is-inside-git-dir")) {
871                                 printf("%s\n", is_inside_git_dir() ? "true"
872                                                 : "false");
873                                 continue;
874                         }
875                         if (!strcmp(arg, "--is-inside-work-tree")) {
876                                 printf("%s\n", is_inside_work_tree() ? "true"
877                                                 : "false");
878                                 continue;
879                         }
880                         if (!strcmp(arg, "--is-bare-repository")) {
881                                 printf("%s\n", is_bare_repository() ? "true"
882                                                 : "false");
883                                 continue;
884                         }
885                         if (!strcmp(arg, "--is-shallow-repository")) {
886                                 printf("%s\n", is_repository_shallow() ? "true"
887                                                 : "false");
888                                 continue;
889                         }
890                         if (!strcmp(arg, "--shared-index-path")) {
891                                 if (read_cache() < 0)
892                                         die(_("Could not read the index"));
893                                 if (the_index.split_index) {
894                                         const struct object_id *oid = &the_index.split_index->base_oid;
895                                         const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
896                                         strbuf_reset(&buf);
897                                         puts(relative_path(path, prefix, &buf));
898                                 }
899                                 continue;
900                         }
901                         if (skip_prefix(arg, "--since=", &arg)) {
902                                 show_datestring("--max-age=", arg);
903                                 continue;
904                         }
905                         if (skip_prefix(arg, "--after=", &arg)) {
906                                 show_datestring("--max-age=", arg);
907                                 continue;
908                         }
909                         if (skip_prefix(arg, "--before=", &arg)) {
910                                 show_datestring("--min-age=", arg);
911                                 continue;
912                         }
913                         if (skip_prefix(arg, "--until=", &arg)) {
914                                 show_datestring("--min-age=", arg);
915                                 continue;
916                         }
917                         if (show_flag(arg) && verify)
918                                 die_no_single_rev(quiet);
919                         continue;
920                 }
921
922                 /* Not a flag argument */
923                 if (try_difference(arg))
924                         continue;
925                 if (try_parent_shorthands(arg))
926                         continue;
927                 name = arg;
928                 type = NORMAL;
929                 if (*arg == '^') {
930                         name++;
931                         type = REVERSED;
932                 }
933                 if (!get_oid_with_context(name, flags, &oid, &unused)) {
934                         if (verify)
935                                 revs_count++;
936                         else
937                                 show_rev(type, &oid, name);
938                         continue;
939                 }
940                 if (verify)
941                         die_no_single_rev(quiet);
942                 if (has_dashdash)
943                         die("bad revision '%s'", arg);
944                 as_is = 1;
945                 if (!show_file(arg, output_prefix))
946                         continue;
947                 verify_filename(prefix, arg, 1);
948         }
949         strbuf_release(&buf);
950         if (verify) {
951                 if (revs_count == 1) {
952                         show_rev(type, &oid, name);
953                         return 0;
954                 } else if (revs_count == 0 && show_default())
955                         return 0;
956                 die_no_single_rev(quiet);
957         } else
958                 show_default();
959         return 0;
960 }