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