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 = startup_info->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, enum format_type format, enum default_type def)
657 {
658 char *cwd = NULL;
659 /*
660 * We don't ever produce a relative path if prefix is NULL, so set the
661 * prefix to the current directory so that we can produce a relative
662 * path whenever possible. If we're using RELATIVE_IF_SHARED mode, then
663 * we want an absolute path unless the two share a common prefix, so don't
664 * set it in that case, since doing so causes a relative path to always
665 * be produced if possible.
666 */
667 if (!prefix && (format != FORMAT_DEFAULT || def != DEFAULT_RELATIVE_IF_SHARED))
668 prefix = cwd = xgetcwd();
669 if (format == FORMAT_DEFAULT && def == DEFAULT_UNMODIFIED) {
670 puts(path);
671 } else if (format == FORMAT_RELATIVE ||
672 (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE)) {
673 /*
674 * In order for relative_path to work as expected, we need to
675 * make sure that both paths are absolute paths. If we don't,
676 * we can end up with an unexpected absolute path that the user
677 * didn't want.
678 */
679 struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
680 if (!is_absolute_path(path)) {
681 strbuf_realpath_forgiving(&realbuf, path, 1);
682 path = realbuf.buf;
683 }
684 if (!is_absolute_path(prefix)) {
685 strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
686 prefix = prefixbuf.buf;
687 }
688 puts(relative_path(path, prefix, &buf));
689 strbuf_release(&buf);
690 strbuf_release(&realbuf);
691 strbuf_release(&prefixbuf);
692 } else if (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE_IF_SHARED) {
693 struct strbuf buf = STRBUF_INIT;
694 puts(relative_path(path, prefix, &buf));
695 strbuf_release(&buf);
696 } else {
697 struct strbuf buf = STRBUF_INIT;
698 strbuf_realpath_forgiving(&buf, path, 1);
699 puts(buf.buf);
700 strbuf_release(&buf);
701 }
702 free(cwd);
703 }
704
705 int cmd_rev_parse(int argc,
706 const char **argv,
707 const char *prefix,
708 struct repository *repo UNUSED)
709 {
710 int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
711 const struct git_hash_algo *output_algo = NULL;
712 const struct git_hash_algo *compat = NULL;
713 int did_repo_setup = 0;
714 int has_dashdash = 0;
715 int output_prefix = 0;
716 struct object_id oid;
717 unsigned int flags = 0;
718 const char *name = NULL;
719 struct strbuf buf = STRBUF_INIT;
720 int seen_end_of_options = 0;
721 enum format_type format = FORMAT_DEFAULT;
722
723 show_usage_if_asked(argc, argv, builtin_rev_parse_usage);
724
725 if (argc > 1 && !strcmp("--parseopt", argv[1]))
726 return cmd_parseopt(argc - 1, argv + 1, prefix);
727
728 if (argc > 1 && !strcmp("--sq-quote", argv[1]))
729 return cmd_sq_quote(argc - 2, argv + 2);
730
731 if (argc > 1 && !strcmp("-h", argv[1]))
732 usage(builtin_rev_parse_usage);
733
734 for (i = 1; i < argc; i++) {
735 if (!strcmp(argv[i], "--")) {
736 has_dashdash = 1;
737 break;
738 }
739 }
740
741 /* No options; just report on whether we're in a git repo or not. */
742 if (argc == 1) {
743 setup_git_directory(the_repository);
744 repo_config(the_repository, git_default_config, NULL);
745 return 0;
746 }
747
748 for (i = 1; i < argc; i++) {
749 const char *arg = argv[i];
750
751 if (as_is) {
752 if (show_file(arg, output_prefix) && as_is < 2)
753 verify_filename(the_repository, prefix, arg, 0);
754 continue;
755 }
756
757 if (!seen_end_of_options) {
758 if (!strcmp(arg, "--local-env-vars")) {
759 int i;
760 for (i = 0; local_repo_env[i]; i++)
761 printf("%s\n", local_repo_env[i]);
762 continue;
763 }
764 if (!strcmp(arg, "--resolve-git-dir")) {
765 const char *gitdir = argv[++i];
766 if (!gitdir)
767 die(_("--resolve-git-dir requires an argument"));
768 gitdir = resolve_gitdir(gitdir);
769 if (!gitdir)
770 die(_("not a gitdir '%s'"), argv[i]);
771 puts(gitdir);
772 continue;
773 }
774 }
775
776 /* The rest of the options require a git repository. */
777 if (!did_repo_setup) {
778 prefix = setup_git_directory(the_repository);
779 repo_config(the_repository, git_default_config, NULL);
780 did_repo_setup = 1;
781
782 prepare_repo_settings(the_repository);
783 the_repository->settings.command_requires_full_index = 0;
784 compat = the_repository->compat_hash_algo;
785 }
786
787 if (!strcmp(arg, "--")) {
788 as_is = 2;
789 /* Pass on the "--" if we show anything but files.. */
790 if (filter & (DO_FLAGS | DO_REVS))
791 show_file(arg, 0);
792 continue;
793 }
794
795 if (!seen_end_of_options && *arg == '-') {
796 if (!strcmp(arg, "--git-path")) {
797 if (!argv[i + 1])
798 die(_("--git-path requires an argument"));
799 print_path(repo_git_path_replace(the_repository, &buf,
800 "%s", argv[i + 1]), prefix,
801 format,
802 DEFAULT_RELATIVE_IF_SHARED);
803 i++;
804 continue;
805 }
806 if (!strcmp(arg,"-n")) {
807 if (++i >= argc)
808 die(_("-n requires an argument"));
809 if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
810 show(arg);
811 show(argv[i]);
812 }
813 continue;
814 }
815 if (starts_with(arg, "-n")) {
816 if ((filter & DO_FLAGS) && (filter & DO_REVS))
817 show(arg);
818 continue;
819 }
820 if (opt_with_value(arg, "--path-format", &arg)) {
821 if (!arg)
822 die(_("--path-format requires an argument"));
823 if (!strcmp(arg, "absolute")) {
824 format = FORMAT_CANONICAL;
825 } else if (!strcmp(arg, "relative")) {
826 format = FORMAT_RELATIVE;
827 } else {
828 die(_("unknown argument to --path-format: %s"), arg);
829 }
830 continue;
831 }
832 if (!strcmp(arg, "--default")) {
833 def = argv[++i];
834 if (!def)
835 die(_("--default requires an argument"));
836 continue;
837 }
838 if (!strcmp(arg, "--prefix")) {
839 prefix = argv[++i];
840 if (!prefix)
841 die(_("--prefix requires an argument"));
842 startup_info->prefix = prefix;
843 output_prefix = 1;
844 continue;
845 }
846 if (!strcmp(arg, "--revs-only")) {
847 filter &= ~DO_NOREV;
848 continue;
849 }
850 if (!strcmp(arg, "--no-revs")) {
851 filter &= ~DO_REVS;
852 continue;
853 }
854 if (!strcmp(arg, "--flags")) {
855 filter &= ~DO_NONFLAGS;
856 continue;
857 }
858 if (!strcmp(arg, "--no-flags")) {
859 filter &= ~DO_FLAGS;
860 continue;
861 }
862 if (!strcmp(arg, "--verify")) {
863 filter &= ~(DO_FLAGS|DO_NOREV);
864 verify = 1;
865 continue;
866 }
867 if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
868 quiet = 1;
869 flags |= GET_OID_QUIETLY;
870 continue;
871 }
872 if (opt_with_value(arg, "--output-object-format", &arg)) {
873 if (!arg)
874 die(_("no object format specified"));
875 if (!strcmp(arg, the_hash_algo->name) ||
876 !strcmp(arg, "storage")) {
877 flags |= GET_OID_HASH_ANY;
878 output_algo = the_hash_algo;
879 continue;
880 }
881 else if (compat && !strcmp(arg, compat->name)) {
882 flags |= GET_OID_HASH_ANY;
883 output_algo = compat;
884 continue;
885 }
886 else die(_("unsupported object format: %s"), arg);
887 }
888 if (opt_with_value(arg, "--short", &arg)) {
889 filter &= ~(DO_FLAGS|DO_NOREV);
890 verify = 1;
891 abbrev = DEFAULT_ABBREV;
892 if (!arg)
893 continue;
894 abbrev = strtoul(arg, NULL, 10);
895 if (abbrev < MINIMUM_ABBREV)
896 abbrev = MINIMUM_ABBREV;
897 else if ((int)the_hash_algo->hexsz <= abbrev)
898 abbrev = the_hash_algo->hexsz;
899 continue;
900 }
901 if (!strcmp(arg, "--sq")) {
902 output_sq = 1;
903 continue;
904 }
905 if (!strcmp(arg, "--not")) {
906 show_type ^= REVERSED;
907 continue;
908 }
909 if (!strcmp(arg, "--symbolic")) {
910 symbolic = SHOW_SYMBOLIC_ASIS;
911 continue;
912 }
913 if (!strcmp(arg, "--symbolic-full-name")) {
914 symbolic = SHOW_SYMBOLIC_FULL;
915 continue;
916 }
917 if (opt_with_value(arg, "--abbrev-ref", &arg)) {
918 abbrev_ref = 1;
919 abbrev_ref_strict =
920 repo_settings_get_warn_ambiguous_refs(the_repository);
921 if (arg) {
922 if (!strcmp(arg, "strict"))
923 abbrev_ref_strict = 1;
924 else if (!strcmp(arg, "loose"))
925 abbrev_ref_strict = 0;
926 else
927 die(_("unknown mode for --abbrev-ref: %s"),
928 arg);
929 }
930 continue;
931 }
932 if (!strcmp(arg, "--all")) {
933 refs_for_each_ref(get_main_ref_store(the_repository),
934 show_reference, NULL);
935 clear_ref_exclusions(&ref_excludes);
936 continue;
937 }
938 if (skip_prefix(arg, "--disambiguate=", &arg)) {
939 repo_for_each_abbrev(the_repository, arg, the_hash_algo,
940 show_abbrev, NULL);
941 continue;
942 }
943 if (!strcmp(arg, "--bisect")) {
944 char *prefix;
945 char *term_bad = NULL;
946 char *term_good = NULL;
947 struct refs_for_each_ref_options opts = { 0 };
948 read_bisect_terms(&term_bad, &term_good);
949 prefix = xstrfmt("refs/bisect/%s", term_bad);
950 opts.prefix = prefix;
951 refs_for_each_ref_ext(get_main_ref_store(the_repository),
952 show_reference, NULL, &opts);
953 free(prefix);
954 prefix = xstrfmt("refs/bisect/%s", term_good);
955 opts.prefix = prefix;
956 refs_for_each_ref_ext(get_main_ref_store(the_repository),
957 anti_reference, NULL, &opts);
958 free(prefix);
959 free(term_good);
960 free(term_bad);
961 continue;
962 }
963 if (opt_with_value(arg, "--branches", &arg)) {
964 if (ref_excludes.hidden_refs_configured)
965 return error(_("options '%s' and '%s' cannot be used together"),
966 "--exclude-hidden", "--branches");
967 handle_ref_opt(arg, "refs/heads/");
968 continue;
969 }
970 if (opt_with_value(arg, "--tags", &arg)) {
971 if (ref_excludes.hidden_refs_configured)
972 return error(_("options '%s' and '%s' cannot be used together"),
973 "--exclude-hidden", "--tags");
974 handle_ref_opt(arg, "refs/tags/");
975 continue;
976 }
977 if (skip_prefix(arg, "--glob=", &arg)) {
978 handle_ref_opt(arg, NULL);
979 continue;
980 }
981 if (opt_with_value(arg, "--remotes", &arg)) {
982 if (ref_excludes.hidden_refs_configured)
983 return error(_("options '%s' and '%s' cannot be used together"),
984 "--exclude-hidden", "--remotes");
985 handle_ref_opt(arg, "refs/remotes/");
986 continue;
987 }
988 if (skip_prefix(arg, "--exclude=", &arg)) {
989 add_ref_exclusion(&ref_excludes, arg);
990 continue;
991 }
992 if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
993 exclude_hidden_refs(&ref_excludes, arg);
994 continue;
995 }
996 if (!strcmp(arg, "--show-toplevel")) {
997 const char *work_tree = repo_get_work_tree(the_repository);
998 if (work_tree)
999 print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
1000 else
1001 die(_("this operation must be run in a work tree"));
1002 continue;
1003 }
1004 if (!strcmp(arg, "--show-superproject-working-tree")) {
1005 struct strbuf superproject = STRBUF_INIT;
1006 if (get_superproject_working_tree(&superproject))
1007 print_path(superproject.buf, prefix, format, DEFAULT_UNMODIFIED);
1008 strbuf_release(&superproject);
1009 continue;
1010 }
1011 if (!strcmp(arg, "--show-prefix")) {
1012 if (prefix)
1013 puts(prefix);
1014 else
1015 putchar('\n');
1016 continue;
1017 }
1018 if (!strcmp(arg, "--show-cdup")) {
1019 const char *pfx = prefix;
1020 if (!is_inside_work_tree(the_repository)) {
1021 const char *work_tree =
1022 repo_get_work_tree(the_repository);
1023 if (work_tree)
1024 printf("%s\n", work_tree);
1025 continue;
1026 }
1027 while (pfx) {
1028 pfx = strchr(pfx, '/');
1029 if (pfx) {
1030 pfx++;
1031 printf("../");
1032 }
1033 }
1034 putchar('\n');
1035 continue;
1036 }
1037 if (!strcmp(arg, "--git-dir") ||
1038 !strcmp(arg, "--absolute-git-dir")) {
1039 const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
1040 char *cwd;
1041 int len;
1042 enum format_type wanted = format;
1043 if (arg[2] == 'g') { /* --git-dir */
1044 if (gitdir) {
1045 print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
1046 continue;
1047 }
1048 if (!prefix) {
1049 print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
1050 continue;
1051 }
1052 } else { /* --absolute-git-dir */
1053 wanted = FORMAT_CANONICAL;
1054 if (!gitdir && !prefix)
1055 gitdir = ".git";
1056 if (gitdir) {
1057 struct strbuf realpath = STRBUF_INIT;
1058 strbuf_realpath(&realpath, gitdir, 1);
1059 puts(realpath.buf);
1060 strbuf_release(&realpath);
1061 continue;
1062 }
1063 }
1064 cwd = xgetcwd();
1065 len = strlen(cwd);
1066 strbuf_reset(&buf);
1067 strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
1068 free(cwd);
1069 print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
1070 continue;
1071 }
1072 if (!strcmp(arg, "--git-common-dir")) {
1073 print_path(repo_get_common_dir(the_repository), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
1074 continue;
1075 }
1076 if (!strcmp(arg, "--is-inside-git-dir")) {
1077 printf("%s\n", is_inside_git_dir(the_repository) ? "true"
1078 : "false");
1079 continue;
1080 }
1081 if (!strcmp(arg, "--is-inside-work-tree")) {
1082 printf("%s\n", is_inside_work_tree(the_repository) ? "true"
1083 : "false");
1084 continue;
1085 }
1086 if (!strcmp(arg, "--is-bare-repository")) {
1087 printf("%s\n", is_bare_repository() ? "true"
1088 : "false");
1089 continue;
1090 }
1091 if (!strcmp(arg, "--is-shallow-repository")) {
1092 printf("%s\n",
1093 is_repository_shallow(the_repository) ? "true"
1094 : "false");
1095 continue;
1096 }
1097 if (!strcmp(arg, "--shared-index-path")) {
1098 if (repo_read_index(the_repository) < 0)
1099 die(_("Could not read the index"));
1100 if (the_repository->index->split_index) {
1101 const struct object_id *oid = &the_repository->index->split_index->base_oid;
1102 const char *path = repo_git_path_replace(the_repository, &buf, "sharedindex.%s", oid_to_hex(oid));
1103 print_path(path, prefix, format, DEFAULT_RELATIVE);
1104 }
1105 continue;
1106 }
1107 if (skip_prefix(arg, "--since=", &arg)) {
1108 show_datestring("--max-age=", arg);
1109 continue;
1110 }
1111 if (skip_prefix(arg, "--after=", &arg)) {
1112 show_datestring("--max-age=", arg);
1113 continue;
1114 }
1115 if (skip_prefix(arg, "--before=", &arg)) {
1116 show_datestring("--min-age=", arg);
1117 continue;
1118 }
1119 if (skip_prefix(arg, "--until=", &arg)) {
1120 show_datestring("--min-age=", arg);
1121 continue;
1122 }
1123 if (opt_with_value(arg, "--show-object-format", &arg)) {
1124 const char *val = arg ? arg : "storage";
1125
1126 if (strcmp(val, "storage") &&
1127 strcmp(val, "compat") &&
1128 strcmp(val, "input") &&
1129 strcmp(val, "output"))
1130 die(_("unknown mode for --show-object-format: %s"),
1131 arg);
1132
1133 if (!strcmp(val, "compat")) {
1134 if (the_repository->compat_hash_algo)
1135 puts(the_repository->compat_hash_algo->name);
1136 else
1137 putchar('\n');
1138 } else {
1139 puts(the_hash_algo->name);
1140 }
1141 continue;
1142 }
1143 if (!strcmp(arg, "--show-ref-format")) {
1144 puts(ref_storage_format_to_name(the_repository->ref_storage_format));
1145 continue;
1146 }
1147 if (!strcmp(arg, "--end-of-options")) {
1148 seen_end_of_options = 1;
1149 if (filter & (DO_FLAGS | DO_REVS))
1150 show_file(arg, 0);
1151 continue;
1152 }
1153 if (show_flag(arg) && verify)
1154 die_no_single_rev(quiet);
1155 continue;
1156 }
1157
1158 /* Not a flag argument */
1159 if (try_difference(arg))
1160 continue;
1161 if (try_parent_shorthands(arg))
1162 continue;
1163 name = arg;
1164 type = NORMAL;
1165 if (*arg == '^') {
1166 name++;
1167 type = REVERSED;
1168 }
1169 if (!repo_get_oid_with_flags(the_repository, name, &oid,
1170 flags)) {
1171 if (output_algo)
1172 repo_oid_to_algop(the_repository, &oid,
1173 output_algo, &oid);
1174 if (verify)
1175 revs_count++;
1176 else
1177 show_rev(type, &oid, name);
1178 continue;
1179 }
1180 if (verify)
1181 die_no_single_rev(quiet);
1182 if (has_dashdash)
1183 die(_("bad revision '%s'"), arg);
1184 as_is = 1;
1185 if (!show_file(arg, output_prefix))
1186 continue;
1187 verify_filename(the_repository, prefix, arg, 1);
1188 }
1189 strbuf_release(&buf);
1190 if (verify) {
1191 if (revs_count == 1) {
1192 show_rev(type, &oid, name);
1193 return 0;
1194 } else if (revs_count == 0 && show_default())
1195 return 0;
1196 die_no_single_rev(quiet);
1197 } else
1198 show_default();
1199 return 0;
1200 }