Raw
1 /*
2 * rev-parse.c
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6
7 #define USE_THE_REPOSITORY_VARIABLE
8 #define DISABLE_SIGN_COMPARE_WARNINGS
9
10 #include "builtin.h"
11
12 #include "abspath.h"
13 #include "bisect.h"
14 #include "config.h"
15 #include "commit.h"
16 #include "environment.h"
17 #include "gettext.h"
18 #include "hash.h"
19 #include "hex.h"
20 #include "refs.h"
21 #include "quote.h"
22 #include "object-name.h"
23 #include "parse-options.h"
24 #include "path.h"
25 #include "diff.h"
26 #include "read-cache-ll.h"
27 #include "repo-settings.h"
28 #include "repository.h"
29 #include "revision.h"
30 #include "setup.h"
31 #include "split-index.h"
32 #include "submodule.h"
33 #include "commit-reach.h"
34 #include "shallow.h"
35 #include "object-file-convert.h"
36
37 #define DO_REVS 1
38 #define DO_NOREV 2
39 #define DO_FLAGS 4
40 #define DO_NONFLAGS 8
41 static int filter = ~0;
42
43 static const char *def;
44
45 #define NORMAL 0
46 #define REVERSED 1
47 static int show_type = NORMAL;
48
49 #define SHOW_SYMBOLIC_ASIS 1
50 #define SHOW_SYMBOLIC_FULL 2
51 static int symbolic;
52 static int abbrev;
53 static int abbrev_ref;
54 static int abbrev_ref_strict;
55 static int output_sq;
56
57 static int stuck_long;
58 static struct ref_exclusions ref_excludes = REF_EXCLUSIONS_INIT;
59
60 /*
61 * Some arguments are relevant "revision" arguments,
62 * others are about output format or other details.
63 * This sorts it all out.
64 */
65 static int is_rev_argument(const char *arg)
66 {
67 static const char *rev_args[] = {
68 "--all",
69 "--bisect",
70 "--dense",
71 "--branches=",
72 "--branches",
73 "--header",
74 "--ignore-missing",
75 "--max-age=",
76 "--max-count=",
77 "--min-age=",
78 "--no-merges",
79 "--min-parents=",
80 "--no-min-parents",
81 "--max-parents=",
82 "--no-max-parents",
83 "--objects",
84 "--objects-edge",
85 "--parents",
86 "--pretty",
87 "--remotes=",
88 "--remotes",
89 "--glob=",
90 "--sparse",
91 "--tags=",
92 "--tags",
93 "--topo-order",
94 "--date-order",
95 "--unpacked",
96 NULL
97 };
98 const char **p = rev_args;
99
100 /* accept -<digit>, like traditional "head" */
101 if ((*arg == '-') && isdigit(arg[1]))
102 return 1;
103
104 for (;;) {
105 const char *str = *p++;
106 int len;
107 if (!str)
108 return 0;
109 len = strlen(str);
110 if (!strcmp(arg, str) ||
111 (str[len-1] == '=' && !strncmp(arg, str, len)))
112 return 1;
113 }
114 }
115
116 /* Output argument as a string, either SQ or normal */
117 static void show(const char *arg)
118 {
119 if (output_sq) {
120 int sq = '\'', ch;
121
122 putchar(sq);
123 while ((ch = *arg++)) {
124 if (ch == sq)
125 fputs("'\\'", stdout);
126 putchar(ch);
127 }
128 putchar(sq);
129 putchar(' ');
130 }
131 else
132 puts(arg);
133 }
134
135 /* Like show(), but with a negation prefix according to type */
136 static void show_with_type(int type, const char *arg)
137 {
138 if (type != show_type)
139 putchar('^');
140 show(arg);
141 }
142
143 /* Output a revision, only if filter allows it */
144 static void show_rev(int type, const struct object_id *oid, const char *name)
145 {
146 if (!(filter & DO_REVS))
147 return;
148 def = NULL;
149
150 if ((symbolic || abbrev_ref) && name) {
151 if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
152 struct object_id discard;
153 char *full;
154
155 switch (repo_dwim_ref(the_repository, name,
156 strlen(name), &discard, &full,
157 0)) {
158 case 0:
159 /*
160 * Not found -- not a ref. We could
161 * emit "name" here, but symbolic-full
162 * users are interested in finding the
163 * refs spelled in full, and they would
164 * need to filter non-refs if we did so.
165 */
166 break;
167 case 1: /* happy */
168 if (abbrev_ref) {
169 char *old = full;
170 full = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
171 full,
172 abbrev_ref_strict);
173 free(old);
174 }
175 show_with_type(type, full);
176 break;
177 default: /* ambiguous */
178 error("refname '%s' is ambiguous", name);
179 break;
180 }
181 free(full);
182 } else {
183 show_with_type(type, name);
184 }
185 }
186 else if (abbrev)
187 show_with_type(type,
188 repo_find_unique_abbrev(the_repository, oid, abbrev));
189 else
190 show_with_type(type, oid_to_hex(oid));
191 }
192
193 /* Output a flag, only if filter allows it. */
194 static int show_flag(const char *arg)
195 {
196 if (!(filter & DO_FLAGS))
197 return 0;
198 if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
199 show(arg);
200 return 1;
201 }
202 return 0;
203 }
204
205 static int show_default(void)
206 {
207 const char *s = def;
208
209 if (s) {
210 struct object_id oid;
211
212 def = NULL;
213 if (!repo_get_oid(the_repository, s, &oid)) {
214 show_rev(NORMAL, &oid, s);
215 return 1;
216 }
217 }
218 return 0;
219 }
220
221 static int show_reference(const struct reference *ref, void *cb_data UNUSED)
222 {
223 if (ref_excluded(&ref_excludes, ref->name))
224 return 0;
225 show_rev(NORMAL, ref->oid, ref->name);
226 return 0;
227 }
228
229 static int anti_reference(const struct reference *ref, void *cb_data UNUSED)
230 {
231 show_rev(REVERSED, ref->oid, ref->name);
232 return 0;
233 }
234
235 static int show_abbrev(const struct object_id *oid, void *cb_data UNUSED)
236 {
237 show_rev(NORMAL, oid, NULL);
238 return 0;
239 }
240
241 static void show_datestring(const char *flag, const char *datestr)
242 {
243 char *buffer;
244
245 /* date handling requires both flags and revs */
246 if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
247 return;
248 buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
249 show(buffer);
250 free(buffer);
251 }
252
253 static int show_file(const char *arg, int output_prefix)
254 {
255 show_default();
256 if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
257 if (output_prefix) {
258 const char *prefix = the_repository->prefix;
259 char *fname = prefix_filename(prefix, arg);
260 show(fname);
261 free(fname);
262 } else
263 show(arg);
264 return 1;
265 }
266 return 0;
267 }
268
269 static int try_difference(const char *arg)
270 {
271 const char *dotdot;
272 struct object_id start_oid;
273 struct object_id end_oid;
274 const char *end;
275 const char *start;
276 char *to_free;
277 int symmetric;
278 static const char head_by_default[] = "HEAD";
279
280 if (!(dotdot = strstr(arg, "..")))
281 return 0;
282 start = to_free = xmemdupz(arg, dotdot - arg);
283 end = dotdot + 2;
284 symmetric = (*end == '.');
285 end += symmetric;
286
287 if (!*end)
288 end = head_by_default;
289 if (dotdot == arg)
290 start = head_by_default;
291
292 if (start == head_by_default && end == head_by_default &&
293 !symmetric) {
294 /*
295 * Just ".."? That is not a range but the
296 * pathspec for the parent directory.
297 */
298 free(to_free);
299 return 0;
300 }
301
302 if (!repo_get_oid_committish(the_repository, start, &start_oid) && !repo_get_oid_committish(the_repository, end, &end_oid)) {
303 show_rev(NORMAL, &end_oid, end);
304 show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
305 if (symmetric) {
306 struct commit_list *exclude = NULL;
307 struct commit *a, *b;
308 a = lookup_commit_reference(the_repository, &start_oid);
309 b = lookup_commit_reference(the_repository, &end_oid);
310 if (!a || !b) {
311 free(to_free);
312 return 0;
313 }
314 if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
315 exit(128);
316 while (exclude) {
317 struct commit *commit = pop_commit(&exclude);
318 show_rev(REVERSED, &commit->object.oid, NULL);
319 }
320 }
321 free(to_free);
322 return 1;
323 }
324 free(to_free);
325 return 0;
326 }
327
328 static int try_parent_shorthands(const char *arg)
329 {
330 const char *mark;
331 struct object_id oid;
332 struct commit *commit;
333 struct commit_list *parents;
334 int parent_number;
335 int include_rev = 0;
336 int include_parents = 0;
337 int exclude_parent = 0;
338 char *to_free;
339
340 if ((mark = strstr(arg, "^!"))) {
341 include_rev = 1;
342 if (mark[2])
343 return 0;
344 } else if ((mark = strstr(arg, "^@"))) {
345 include_parents = 1;
346 if (mark[2])
347 return 0;
348 } else if ((mark = strstr(arg, "^-"))) {
349 include_rev = 1;
350 exclude_parent = 1;
351
352 if (mark[2]) {
353 char *end;
354 exclude_parent = strtoul(mark + 2, &end, 10);
355 if (*end != '\0' || !exclude_parent)
356 return 0;
357 }
358 } else
359 return 0;
360
361 arg = to_free = xmemdupz(arg, mark - arg);
362 if (repo_get_oid_committish(the_repository, arg, &oid) ||
363 !(commit = lookup_commit_reference(the_repository, &oid))) {
364 free(to_free);
365 return 0;
366 }
367
368 if (exclude_parent &&
369 exclude_parent > commit_list_count(commit->parents)) {
370 free(to_free);
371 return 0;
372 }
373
374 if (include_rev)
375 show_rev(NORMAL, &oid, arg);
376 for (parents = commit->parents, parent_number = 1;
377 parents;
378 parents = parents->next, parent_number++) {
379 char *name = NULL;
380
381 if (exclude_parent && parent_number != exclude_parent)
382 continue;
383
384 if (symbolic)
385 name = xstrfmt("%s^%d", arg, parent_number);
386 show_rev(include_parents ? NORMAL : REVERSED,
387 &parents->item->object.oid, name);
388 free(name);
389 }
390
391 free(to_free);
392 return 1;
393 }
394
395 static int parseopt_dump(const struct option *o, const char *arg, int unset)
396 {
397 struct strbuf *parsed = o->value;
398 if (unset)
399 strbuf_addf(parsed, " --no-%s", o->long_name);
400 else if (o->short_name && (o->long_name == NULL || !stuck_long))
401 strbuf_addf(parsed, " -%c", o->short_name);
402 else
403 strbuf_addf(parsed, " --%s", o->long_name);
404 if (arg) {
405 if (!stuck_long)
406 strbuf_addch(parsed, ' ');
407 else if (o->long_name)
408 strbuf_addch(parsed, '=');
409 sq_quote_buf(parsed, arg);
410 }
411 return 0;
412 }
413
414 static const char *skipspaces(const char *s)
415 {
416 while (isspace(*s))
417 s++;
418 return s;
419 }
420
421 static char *findspace(const char *s)
422 {
423 for (; *s; s++)
424 if (isspace(*s))
425 return (char*)s;
426 return NULL;
427 }
428
429 static int cmd_parseopt(int argc, const char **argv, const char *prefix)
430 {
431 int keep_dashdash = 0, stop_at_non_option = 0;
432 char const * const parseopt_usage[] = {
433 N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
434 NULL
435 };
436 struct option parseopt_opts[] = {
437 OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
438 N_("keep the `--` passed as an arg")),
439 OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
440 N_("stop parsing after the "
441 "first non-option argument")),
442 OPT_BOOL(0, "stuck-long", &stuck_long,
443 N_("output in stuck long form")),
444 OPT_END(),
445 };
446 struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
447 struct strvec longnames = STRVEC_INIT;
448 struct strvec usage = STRVEC_INIT;
449 struct option *opts = NULL;
450 size_t opts_nr = 0, opts_alloc = 0;
451
452 strbuf_addstr(&parsed, "set --");
453 argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
454 PARSE_OPT_KEEP_DASHDASH);
455 if (argc < 1 || strcmp(argv[0], "--"))
456 usage_with_options(parseopt_usage, parseopt_opts);
457
458 /* get the usage up to the first line with a -- on it */
459 for (;;) {
460 strbuf_reset(&sb);
461 if (strbuf_getline(&sb, stdin) == EOF)
462 die(_("premature end of input"));
463 if (!strcmp("--", sb.buf)) {
464 if (!usage.nr)
465 die(_("no usage string given before the `--' separator"));
466 break;
467 }
468
469 strvec_push(&usage, sb.buf);
470 }
471
472 /* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
473 while (strbuf_getline(&sb, stdin) != EOF) {
474 const char *s;
475 char *help;
476 struct option *o;
477
478 if (!sb.len)
479 continue;
480
481 ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
482 memset(opts + opts_nr, 0, sizeof(*opts));
483
484 o = &opts[opts_nr++];
485 help = findspace(sb.buf);
486 if (!help || sb.buf == help) {
487 o->type = OPTION_GROUP;
488 o->help = xstrdup(skipspaces(sb.buf));
489 continue;
490 }
491
492 *help = '\0';
493
494 o->type = OPTION_CALLBACK;
495 o->help = xstrdup(skipspaces(help+1));
496 o->value = &parsed;
497 o->flags = PARSE_OPT_NOARG;
498 o->callback = &parseopt_dump;
499
500 /* name(s) */
501 s = strpbrk(sb.buf, "*=?!");
502 if (!s)
503 s = help;
504
505 if (s == sb.buf)
506 die(_("missing opt-spec before option flags"));
507
508 if (s - sb.buf == 1) { /* short option only */
509 o->short_name = *sb.buf;
510 } else if (sb.buf[1] != ',') { /* long option only */
511 o->long_name = strvec_pushf(&longnames, "%.*s",
512 (int)(s - sb.buf), sb.buf);
513 } else {
514 o->short_name = *sb.buf;
515 o->long_name = strvec_pushf(&longnames, "%.*s",
516 (int)(s - sb.buf - 2), sb.buf + 2);
517 }
518
519 /* flags */
520 while (s < help) {
521 switch (*s++) {
522 case '=':
523 o->flags &= ~PARSE_OPT_NOARG;
524 continue;
525 case '?':
526 o->flags &= ~PARSE_OPT_NOARG;
527 o->flags |= PARSE_OPT_OPTARG;
528 continue;
529 case '!':
530 o->flags |= PARSE_OPT_NONEG;
531 continue;
532 case '*':
533 o->flags |= PARSE_OPT_HIDDEN;
534 continue;
535 }
536 s--;
537 break;
538 }
539
540 if (s < help)
541 o->argh = xmemdupz(s, help - s);
542 }
543 strbuf_release(&sb);
544
545 /* put an OPT_END() */
546 ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
547 memset(opts + opts_nr, 0, sizeof(*opts));
548 argc = parse_options(argc, argv, prefix, opts, usage.v,
549 (keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
550 (stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
551 PARSE_OPT_SHELL_EVAL);
552
553 strbuf_addstr(&parsed, " --");
554 sq_quote_argv(&parsed, argv);
555 puts(parsed.buf);
556
557 strbuf_release(&parsed);
558 strbuf_release(&sb);
559 strvec_clear(&longnames);
560 strvec_clear(&usage);
561 for (size_t i = 0; i < opts_nr; i++) {
562 free((char *) opts[i].help);
563 free((char *) opts[i].argh);
564 }
565 free(opts);
566 return 0;
567 }
568
569 static int cmd_sq_quote(int argc, const char **argv)
570 {
571 struct strbuf buf = STRBUF_INIT;
572
573 if (argc)
574 sq_quote_argv(&buf, argv);
575 printf("%s\n", buf.buf);
576 strbuf_release(&buf);
577
578 return 0;
579 }
580
581 static void die_no_single_rev(int quiet)
582 {
583 if (quiet)
584 exit(1);
585 else
586 die(_("Needed a single revision"));
587 }
588
589 static const char builtin_rev_parse_usage[] =
590 N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
591 " or: git rev-parse --sq-quote [<arg>...]\n"
592 " or: git rev-parse [<options>] [<arg>...]\n"
593 "\n"
594 "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
595
596 /*
597 * Parse "opt" or "opt=<value>", setting value respectively to either
598 * NULL or the string after "=".
599 */
600 static int opt_with_value(const char *arg, const char *opt, const char **value)
601 {
602 if (skip_prefix(arg, opt, &arg)) {
603 if (!*arg) {
604 *value = NULL;
605 return 1;
606 }
607 if (*arg++ == '=') {
608 *value = arg;
609 return 1;
610 }
611 }
612 return 0;
613 }
614
615 static void handle_ref_opt(const char *pattern, const char *prefix)
616 {
617 if (pattern) {
618 struct refs_for_each_ref_options opts = {
619 .pattern = pattern,
620 .prefix = prefix,
621 .trim_prefix = prefix ? strlen(prefix) : 0,
622 };
623 refs_for_each_ref_ext(get_main_ref_store(the_repository),
624 show_reference, NULL, &opts);
625 } else {
626 struct refs_for_each_ref_options opts = {
627 .prefix = prefix,
628 .trim_prefix = strlen(prefix),
629 };
630 refs_for_each_ref_ext(get_main_ref_store(the_repository),
631 show_reference, NULL, &opts);
632 }
633 clear_ref_exclusions(&ref_excludes);
634 }
635
636 enum format_type {
637 /* We would like a relative path. */
638 FORMAT_RELATIVE,
639 /* We would like a canonical absolute path. */
640 FORMAT_CANONICAL,
641 /* We would like the default behavior. */
642 FORMAT_DEFAULT,
643 };
644
645 enum default_type {
646 /* Our default is a relative path. */
647 DEFAULT_RELATIVE,
648 /* Our default is a relative path if there's a shared root. */
649 DEFAULT_RELATIVE_IF_SHARED,
650 /* Our default is a canonical absolute path. */
651 DEFAULT_CANONICAL,
652 /* Our default is not to modify the item. */
653 DEFAULT_UNMODIFIED,
654 };
655
656 static void print_path(const char *path, const char *prefix,
657 enum format_type format, enum default_type def)
658 {
659 struct strbuf sb = STRBUF_INIT;
660 enum path_format fmt;
661
662 if (format == FORMAT_DEFAULT) {
663 switch (def) {
664 case DEFAULT_RELATIVE:
665 fmt = PATH_FORMAT_RELATIVE;
666 break;
667 case DEFAULT_RELATIVE_IF_SHARED:
668 fmt = PATH_FORMAT_RELATIVE_IF_SHARED;
669 break;
670 case DEFAULT_CANONICAL:
671 fmt = PATH_FORMAT_CANONICAL;
672 break;
673 case DEFAULT_UNMODIFIED:
674 default:
675 fmt = PATH_FORMAT_UNMODIFIED;
676 break;
677 }
678 } else {
679 switch (format) {
680 case FORMAT_RELATIVE:
681 fmt = PATH_FORMAT_RELATIVE;
682 break;
683 case FORMAT_CANONICAL:
684 fmt = PATH_FORMAT_CANONICAL;
685 break;
686 default:
687 fmt = PATH_FORMAT_UNMODIFIED;
688 break;
689 }
690 }
691
692 format_path(&sb, path, prefix, fmt);
693 puts(sb.buf);
694
695 strbuf_release(&sb);
696 }
697
698 int cmd_rev_parse(int argc,
699 const char **argv,
700 const char *prefix,
701 struct repository *repo UNUSED)
702 {
703 int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
704 const struct git_hash_algo *output_algo = NULL;
705 const struct git_hash_algo *compat = NULL;
706 int did_repo_setup = 0;
707 int has_dashdash = 0;
708 int output_prefix = 0;
709 struct object_id oid;
710 unsigned int flags = 0;
711 const char *name = NULL;
712 struct strbuf buf = STRBUF_INIT;
713 int seen_end_of_options = 0;
714 enum format_type format = FORMAT_DEFAULT;
715
716 show_usage_if_asked(argc, argv, builtin_rev_parse_usage);
717
718 if (argc > 1 && !strcmp("--parseopt", argv[1]))
719 return cmd_parseopt(argc - 1, argv + 1, prefix);
720
721 if (argc > 1 && !strcmp("--sq-quote", argv[1]))
722 return cmd_sq_quote(argc - 2, argv + 2);
723
724 if (argc > 1 && !strcmp("-h", argv[1]))
725 usage(builtin_rev_parse_usage);
726
727 for (i = 1; i < argc; i++) {
728 if (!strcmp(argv[i], "--")) {
729 has_dashdash = 1;
730 break;
731 }
732 }
733
734 /* No options; just report on whether we're in a git repo or not. */
735 if (argc == 1) {
736 setup_git_directory(the_repository);
737 repo_config(the_repository, git_default_config, NULL);
738 return 0;
739 }
740
741 for (i = 1; i < argc; i++) {
742 const char *arg = argv[i];
743
744 if (as_is) {
745 if (show_file(arg, output_prefix) && as_is < 2)
746 verify_filename(the_repository, prefix, arg, 0);
747 continue;
748 }
749
750 if (!seen_end_of_options) {
751 if (!strcmp(arg, "--local-env-vars")) {
752 int i;
753 for (i = 0; local_repo_env[i]; i++)
754 printf("%s\n", local_repo_env[i]);
755 continue;
756 }
757 if (!strcmp(arg, "--resolve-git-dir")) {
758 const char *gitdir = argv[++i];
759 if (!gitdir)
760 die(_("--resolve-git-dir requires an argument"));
761 gitdir = resolve_gitdir(gitdir);
762 if (!gitdir)
763 die(_("not a gitdir '%s'"), argv[i]);
764 puts(gitdir);
765 continue;
766 }
767 }
768
769 /* The rest of the options require a git repository. */
770 if (!did_repo_setup) {
771 prefix = setup_git_directory(the_repository);
772 repo_config(the_repository, git_default_config, NULL);
773 did_repo_setup = 1;
774
775 prepare_repo_settings(the_repository);
776 the_repository->settings.command_requires_full_index = 0;
777 compat = the_repository->compat_hash_algo;
778 }
779
780 if (!strcmp(arg, "--")) {
781 as_is = 2;
782 /* Pass on the "--" if we show anything but files.. */
783 if (filter & (DO_FLAGS | DO_REVS))
784 show_file(arg, 0);
785 continue;
786 }
787
788 if (!seen_end_of_options && *arg == '-') {
789 if (!strcmp(arg, "--git-path")) {
790 if (!argv[i + 1])
791 die(_("--git-path requires an argument"));
792 print_path(repo_git_path_replace(the_repository, &buf,
793 "%s", argv[i + 1]), prefix,
794 format,
795 DEFAULT_RELATIVE_IF_SHARED);
796 i++;
797 continue;
798 }
799 if (!strcmp(arg,"-n")) {
800 if (++i >= argc)
801 die(_("-n requires an argument"));
802 if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
803 show(arg);
804 show(argv[i]);
805 }
806 continue;
807 }
808 if (starts_with(arg, "-n")) {
809 if ((filter & DO_FLAGS) && (filter & DO_REVS))
810 show(arg);
811 continue;
812 }
813 if (opt_with_value(arg, "--path-format", &arg)) {
814 if (!arg)
815 die(_("--path-format requires an argument"));
816 if (!strcmp(arg, "absolute")) {
817 format = FORMAT_CANONICAL;
818 } else if (!strcmp(arg, "relative")) {
819 format = FORMAT_RELATIVE;
820 } else {
821 die(_("unknown argument to --path-format: %s"), arg);
822 }
823 continue;
824 }
825 if (!strcmp(arg, "--default")) {
826 def = argv[++i];
827 if (!def)
828 die(_("--default requires an argument"));
829 continue;
830 }
831 if (!strcmp(arg, "--prefix")) {
832 prefix = argv[++i];
833 if (!prefix)
834 die(_("--prefix requires an argument"));
835 FREE_AND_NULL(the_repository->prefix);
836 the_repository->prefix = xstrdup(prefix);
837 output_prefix = 1;
838 continue;
839 }
840 if (!strcmp(arg, "--revs-only")) {
841 filter &= ~DO_NOREV;
842 continue;
843 }
844 if (!strcmp(arg, "--no-revs")) {
845 filter &= ~DO_REVS;
846 continue;
847 }
848 if (!strcmp(arg, "--flags")) {
849 filter &= ~DO_NONFLAGS;
850 continue;
851 }
852 if (!strcmp(arg, "--no-flags")) {
853 filter &= ~DO_FLAGS;
854 continue;
855 }
856 if (!strcmp(arg, "--verify")) {
857 filter &= ~(DO_FLAGS|DO_NOREV);
858 verify = 1;
859 continue;
860 }
861 if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
862 quiet = 1;
863 flags |= GET_OID_QUIETLY;
864 continue;
865 }
866 if (opt_with_value(arg, "--output-object-format", &arg)) {
867 if (!arg)
868 die(_("no object format specified"));
869 if (!strcmp(arg, the_hash_algo->name) ||
870 !strcmp(arg, "storage")) {
871 flags |= GET_OID_HASH_ANY;
872 output_algo = the_hash_algo;
873 continue;
874 }
875 else if (compat && !strcmp(arg, compat->name)) {
876 flags |= GET_OID_HASH_ANY;
877 output_algo = compat;
878 continue;
879 }
880 else die(_("unsupported object format: %s"), arg);
881 }
882 if (opt_with_value(arg, "--short", &arg)) {
883 filter &= ~(DO_FLAGS|DO_NOREV);
884 verify = 1;
885 abbrev = DEFAULT_ABBREV;
886 if (!arg)
887 continue;
888 abbrev = strtoul(arg, NULL, 10);
889 if (abbrev < MINIMUM_ABBREV)
890 abbrev = MINIMUM_ABBREV;
891 else if ((int)the_hash_algo->hexsz <= abbrev)
892 abbrev = the_hash_algo->hexsz;
893 continue;
894 }
895 if (!strcmp(arg, "--sq")) {
896 output_sq = 1;
897 continue;
898 }
899 if (!strcmp(arg, "--not")) {
900 show_type ^= REVERSED;
901 continue;
902 }
903 if (!strcmp(arg, "--symbolic")) {
904 symbolic = SHOW_SYMBOLIC_ASIS;
905 continue;
906 }
907 if (!strcmp(arg, "--symbolic-full-name")) {
908 symbolic = SHOW_SYMBOLIC_FULL;
909 continue;
910 }
911 if (opt_with_value(arg, "--abbrev-ref", &arg)) {
912 abbrev_ref = 1;
913 abbrev_ref_strict =
914 repo_settings_get_warn_ambiguous_refs(the_repository);
915 if (arg) {
916 if (!strcmp(arg, "strict"))
917 abbrev_ref_strict = 1;
918 else if (!strcmp(arg, "loose"))
919 abbrev_ref_strict = 0;
920 else
921 die(_("unknown mode for --abbrev-ref: %s"),
922 arg);
923 }
924 continue;
925 }
926 if (!strcmp(arg, "--all")) {
927 refs_for_each_ref(get_main_ref_store(the_repository),
928 show_reference, NULL);
929 clear_ref_exclusions(&ref_excludes);
930 continue;
931 }
932 if (skip_prefix(arg, "--disambiguate=", &arg)) {
933 repo_for_each_abbrev(the_repository, arg, the_hash_algo,
934 show_abbrev, NULL);
935 continue;
936 }
937 if (!strcmp(arg, "--bisect")) {
938 char *prefix;
939 char *term_bad = NULL;
940 char *term_good = NULL;
941 struct refs_for_each_ref_options opts = { 0 };
942 read_bisect_terms(&term_bad, &term_good);
943 prefix = xstrfmt("refs/bisect/%s", term_bad);
944 opts.prefix = prefix;
945 refs_for_each_ref_ext(get_main_ref_store(the_repository),
946 show_reference, NULL, &opts);
947 free(prefix);
948 prefix = xstrfmt("refs/bisect/%s", term_good);
949 opts.prefix = prefix;
950 refs_for_each_ref_ext(get_main_ref_store(the_repository),
951 anti_reference, NULL, &opts);
952 free(prefix);
953 free(term_good);
954 free(term_bad);
955 continue;
956 }
957 if (opt_with_value(arg, "--branches", &arg)) {
958 if (ref_excludes.hidden_refs_configured)
959 return error(_("options '%s' and '%s' cannot be used together"),
960 "--exclude-hidden", "--branches");
961 handle_ref_opt(arg, "refs/heads/");
962 continue;
963 }
964 if (opt_with_value(arg, "--tags", &arg)) {
965 if (ref_excludes.hidden_refs_configured)
966 return error(_("options '%s' and '%s' cannot be used together"),
967 "--exclude-hidden", "--tags");
968 handle_ref_opt(arg, "refs/tags/");
969 continue;
970 }
971 if (skip_prefix(arg, "--glob=", &arg)) {
972 handle_ref_opt(arg, NULL);
973 continue;
974 }
975 if (opt_with_value(arg, "--remotes", &arg)) {
976 if (ref_excludes.hidden_refs_configured)
977 return error(_("options '%s' and '%s' cannot be used together"),
978 "--exclude-hidden", "--remotes");
979 handle_ref_opt(arg, "refs/remotes/");
980 continue;
981 }
982 if (skip_prefix(arg, "--exclude=", &arg)) {
983 add_ref_exclusion(&ref_excludes, arg);
984 continue;
985 }
986 if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
987 exclude_hidden_refs(&ref_excludes, arg);
988 continue;
989 }
990 if (!strcmp(arg, "--show-toplevel")) {
991 const char *work_tree = repo_get_work_tree(the_repository);
992 if (work_tree)
993 print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
994 else
995 die(_("this operation must be run in a work tree"));
996 continue;
997 }
998 if (!strcmp(arg, "--show-superproject-working-tree")) {
999 struct strbuf superproject = STRBUF_INIT;
1000 if (get_superproject_working_tree(&superproject))
1001 print_path(superproject.buf, prefix, format, DEFAULT_UNMODIFIED);
1002 strbuf_release(&superproject);
1003 continue;
1004 }
1005 if (!strcmp(arg, "--show-prefix")) {
1006 if (prefix)
1007 puts(prefix);
1008 else
1009 putchar('\n');
1010 continue;
1011 }
1012 if (!strcmp(arg, "--show-cdup")) {
1013 const char *pfx = prefix;
1014 if (!is_inside_work_tree(the_repository)) {
1015 const char *work_tree =
1016 repo_get_work_tree(the_repository);
1017 if (work_tree)
1018 printf("%s\n", work_tree);
1019 continue;
1020 }
1021 while (pfx) {
1022 pfx = strchr(pfx, '/');
1023 if (pfx) {
1024 pfx++;
1025 printf("../");
1026 }
1027 }
1028 putchar('\n');
1029 continue;
1030 }
1031 if (!strcmp(arg, "--git-dir") ||
1032 !strcmp(arg, "--absolute-git-dir")) {
1033 const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
1034 char *cwd;
1035 int len;
1036 enum format_type wanted = format;
1037 if (arg[2] == 'g') { /* --git-dir */
1038 if (gitdir) {
1039 print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
1040 continue;
1041 }
1042 if (!prefix) {
1043 print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
1044 continue;
1045 }
1046 } else { /* --absolute-git-dir */
1047 wanted = FORMAT_CANONICAL;
1048 if (!gitdir && !prefix)
1049 gitdir = ".git";
1050 if (gitdir) {
1051 struct strbuf realpath = STRBUF_INIT;
1052 strbuf_realpath(&realpath, gitdir, 1);
1053 puts(realpath.buf);
1054 strbuf_release(&realpath);
1055 continue;
1056 }
1057 }
1058 cwd = xgetcwd();
1059 len = strlen(cwd);
1060 strbuf_reset(&buf);
1061 strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
1062 free(cwd);
1063 print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
1064 continue;
1065 }
1066 if (!strcmp(arg, "--git-common-dir")) {
1067 print_path(repo_get_common_dir(the_repository), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
1068 continue;
1069 }
1070 if (!strcmp(arg, "--is-inside-git-dir")) {
1071 printf("%s\n", is_inside_git_dir(the_repository) ? "true"
1072 : "false");
1073 continue;
1074 }
1075 if (!strcmp(arg, "--is-inside-work-tree")) {
1076 printf("%s\n", is_inside_work_tree(the_repository) ? "true"
1077 : "false");
1078 continue;
1079 }
1080 if (!strcmp(arg, "--is-bare-repository")) {
1081 printf("%s\n", is_bare_repository(the_repository) ? "true"
1082 : "false");
1083 continue;
1084 }
1085 if (!strcmp(arg, "--is-shallow-repository")) {
1086 printf("%s\n",
1087 is_repository_shallow(the_repository) ? "true"
1088 : "false");
1089 continue;
1090 }
1091 if (!strcmp(arg, "--shared-index-path")) {
1092 if (repo_read_index(the_repository) < 0)
1093 die(_("Could not read the index"));
1094 if (the_repository->index->split_index) {
1095 const struct object_id *oid = &the_repository->index->split_index->base_oid;
1096 const char *path = repo_git_path_replace(the_repository, &buf, "sharedindex.%s", oid_to_hex(oid));
1097 print_path(path, prefix, format, DEFAULT_RELATIVE);
1098 }
1099 continue;
1100 }
1101 if (skip_prefix(arg, "--since=", &arg)) {
1102 show_datestring("--max-age=", arg);
1103 continue;
1104 }
1105 if (skip_prefix(arg, "--after=", &arg)) {
1106 show_datestring("--max-age=", arg);
1107 continue;
1108 }
1109 if (skip_prefix(arg, "--before=", &arg)) {
1110 show_datestring("--min-age=", arg);
1111 continue;
1112 }
1113 if (skip_prefix(arg, "--until=", &arg)) {
1114 show_datestring("--min-age=", arg);
1115 continue;
1116 }
1117 if (opt_with_value(arg, "--show-object-format", &arg)) {
1118 const char *val = arg ? arg : "storage";
1119
1120 if (strcmp(val, "storage") &&
1121 strcmp(val, "compat") &&
1122 strcmp(val, "input") &&
1123 strcmp(val, "output"))
1124 die(_("unknown mode for --show-object-format: %s"),
1125 arg);
1126
1127 if (!strcmp(val, "compat")) {
1128 if (the_repository->compat_hash_algo)
1129 puts(the_repository->compat_hash_algo->name);
1130 else
1131 putchar('\n');
1132 } else {
1133 puts(the_hash_algo->name);
1134 }
1135 continue;
1136 }
1137 if (!strcmp(arg, "--show-ref-format")) {
1138 puts(ref_storage_format_to_name(the_repository->ref_storage_format));
1139 continue;
1140 }
1141 if (!strcmp(arg, "--end-of-options")) {
1142 seen_end_of_options = 1;
1143 if (filter & (DO_FLAGS | DO_REVS))
1144 show_file(arg, 0);
1145 continue;
1146 }
1147 if (show_flag(arg) && verify)
1148 die_no_single_rev(quiet);
1149 continue;
1150 }
1151
1152 /* Not a flag argument */
1153 if (try_difference(arg))
1154 continue;
1155 if (try_parent_shorthands(arg))
1156 continue;
1157 name = arg;
1158 type = NORMAL;
1159 if (*arg == '^') {
1160 name++;
1161 type = REVERSED;
1162 }
1163 if (!repo_get_oid_with_flags(the_repository, name, &oid,
1164 flags)) {
1165 if (output_algo)
1166 repo_oid_to_algop(the_repository, &oid,
1167 output_algo, &oid);
1168 if (verify)
1169 revs_count++;
1170 else
1171 show_rev(type, &oid, name);
1172 continue;
1173 }
1174 if (verify)
1175 die_no_single_rev(quiet);
1176 if (has_dashdash)
1177 die(_("bad revision '%s'"), arg);
1178 as_is = 1;
1179 if (!show_file(arg, output_prefix))
1180 continue;
1181 verify_filename(the_repository, prefix, arg, 1);
1182 }
1183 strbuf_release(&buf);
1184 if (verify) {
1185 if (revs_count == 1) {
1186 show_rev(type, &oid, name);
1187 return 0;
1188 } else if (revs_count == 0 && show_default())
1189 return 0;
1190 die_no_single_rev(quiet);
1191 } else
1192 show_default();
1193 return 0;
1194 }