Git fork

Merge branch 'jk/rev-parse-end-of-options'

"git rev-parse" learned the "--end-of-options" to help scripts to
safely take a parameter that is supposed to be a revision, e.g.
"git rev-parse --verify -q --end-of-options $rev".

* jk/rev-parse-end-of-options:
rev-parse: handle --end-of-options
rev-parse: put all options under the "-" check
rev-parse: don't accept options after dashdash

+99 -47
+6 -2
Documentation/git-rev-parse.txt
··· 109 109 annotated tag that points at a commit). To make sure that `$VAR` 110 110 names an existing object of any type, `git rev-parse "$VAR^{object}"` 111 111 can be used. 112 + + 113 + Note that if you are verifying a name from an untrusted source, it is 114 + wise to use `--end-of-options` so that the name argument is not mistaken 115 + for another option. 112 116 113 117 -q:: 114 118 --quiet:: ··· 446 450 * Print the commit object name from the revision in the $REV shell variable: 447 451 + 448 452 ------------ 449 - $ git rev-parse --verify $REV^{commit} 453 + $ git rev-parse --verify --end-of-options $REV^{commit} 450 454 ------------ 451 455 + 452 456 This will error out if $REV is empty or not a valid revision. ··· 454 458 * Similar to above: 455 459 + 456 460 ------------ 457 - $ git rev-parse --default master --verify $REV 461 + $ git rev-parse --default master --verify --end-of-options $REV 458 462 ------------ 459 463 + 460 464 but if $REV is empty, the commit object name from master will be printed.
+55 -45
builtin/rev-parse.c
··· 595 595 struct object_context unused; 596 596 struct strbuf buf = STRBUF_INIT; 597 597 const int hexsz = the_hash_algo->hexsz; 598 + int seen_end_of_options = 0; 598 599 599 600 if (argc > 1 && !strcmp("--parseopt", argv[1])) 600 601 return cmd_parseopt(argc - 1, argv + 1, prefix); ··· 622 623 for (i = 1; i < argc; i++) { 623 624 const char *arg = argv[i]; 624 625 625 - if (!strcmp(arg, "--local-env-vars")) { 626 - int i; 627 - for (i = 0; local_repo_env[i]; i++) 628 - printf("%s\n", local_repo_env[i]); 626 + if (as_is) { 627 + if (show_file(arg, output_prefix) && as_is < 2) 628 + verify_filename(prefix, arg, 0); 629 629 continue; 630 630 } 631 - if (!strcmp(arg, "--resolve-git-dir")) { 632 - const char *gitdir = argv[++i]; 633 - if (!gitdir) 634 - die("--resolve-git-dir requires an argument"); 635 - gitdir = resolve_gitdir(gitdir); 636 - if (!gitdir) 637 - die("not a gitdir '%s'", argv[i]); 638 - puts(gitdir); 639 - continue; 631 + 632 + if (!seen_end_of_options) { 633 + if (!strcmp(arg, "--local-env-vars")) { 634 + int i; 635 + for (i = 0; local_repo_env[i]; i++) 636 + printf("%s\n", local_repo_env[i]); 637 + continue; 638 + } 639 + if (!strcmp(arg, "--resolve-git-dir")) { 640 + const char *gitdir = argv[++i]; 641 + if (!gitdir) 642 + die("--resolve-git-dir requires an argument"); 643 + gitdir = resolve_gitdir(gitdir); 644 + if (!gitdir) 645 + die("not a gitdir '%s'", argv[i]); 646 + puts(gitdir); 647 + continue; 648 + } 640 649 } 641 650 642 651 /* The rest of the options require a git repository. */ ··· 646 655 did_repo_setup = 1; 647 656 } 648 657 649 - if (!strcmp(arg, "--git-path")) { 650 - if (!argv[i + 1]) 651 - die("--git-path requires an argument"); 652 - strbuf_reset(&buf); 653 - puts(relative_path(git_path("%s", argv[i + 1]), 654 - prefix, &buf)); 655 - i++; 656 - continue; 657 - } 658 - if (as_is) { 659 - if (show_file(arg, output_prefix) && as_is < 2) 660 - verify_filename(prefix, arg, 0); 658 + if (!strcmp(arg, "--")) { 659 + as_is = 2; 660 + /* Pass on the "--" if we show anything but files.. */ 661 + if (filter & (DO_FLAGS | DO_REVS)) 662 + show_file(arg, 0); 661 663 continue; 662 664 } 663 - if (!strcmp(arg,"-n")) { 664 - if (++i >= argc) 665 - die("-n requires an argument"); 666 - if ((filter & DO_FLAGS) && (filter & DO_REVS)) { 667 - show(arg); 668 - show(argv[i]); 665 + 666 + if (!seen_end_of_options && *arg == '-') { 667 + if (!strcmp(arg, "--git-path")) { 668 + if (!argv[i + 1]) 669 + die("--git-path requires an argument"); 670 + strbuf_reset(&buf); 671 + puts(relative_path(git_path("%s", argv[i + 1]), 672 + prefix, &buf)); 673 + i++; 674 + continue; 675 + } 676 + if (!strcmp(arg,"-n")) { 677 + if (++i >= argc) 678 + die("-n requires an argument"); 679 + if ((filter & DO_FLAGS) && (filter & DO_REVS)) { 680 + show(arg); 681 + show(argv[i]); 682 + } 683 + continue; 669 684 } 670 - continue; 671 - } 672 - if (starts_with(arg, "-n")) { 673 - if ((filter & DO_FLAGS) && (filter & DO_REVS)) 674 - show(arg); 675 - continue; 676 - } 677 - 678 - if (*arg == '-') { 679 - if (!strcmp(arg, "--")) { 680 - as_is = 2; 681 - /* Pass on the "--" if we show anything but files.. */ 682 - if (filter & (DO_FLAGS | DO_REVS)) 683 - show_file(arg, 0); 685 + if (starts_with(arg, "-n")) { 686 + if ((filter & DO_FLAGS) && (filter & DO_REVS)) 687 + show(arg); 684 688 continue; 685 689 } 686 690 if (!strcmp(arg, "--default")) { ··· 935 939 die("unknown mode for --show-object-format: %s", 936 940 arg); 937 941 puts(the_hash_algo->name); 942 + continue; 943 + } 944 + if (!strcmp(arg, "--end-of-options")) { 945 + seen_end_of_options = 1; 946 + if (filter & (DO_FLAGS | DO_REVS)) 947 + show_file(arg, 0); 938 948 continue; 939 949 } 940 950 if (show_flag(arg) && verify)
+13
t/t1503-rev-parse-verify.sh
··· 144 144 test_must_fail git rev-parse --verify broken 145 145 ' 146 146 147 + test_expect_success 'options can appear after --verify' ' 148 + git rev-parse --verify HEAD >expect && 149 + git rev-parse --verify -q HEAD >actual && 150 + test_cmp expect actual 151 + ' 152 + 153 + test_expect_success 'verify respects --end-of-options' ' 154 + git update-ref refs/heads/-tricky HEAD && 155 + git rev-parse --verify HEAD >expect && 156 + git rev-parse --verify --end-of-options -tricky >actual && 157 + test_cmp expect actual 158 + ' 159 + 147 160 test_done
+25
t/t1506-rev-parse-diagnosis.sh
··· 254 254 test_must_fail git rev-parse "foo\\*bar" 255 255 ' 256 256 257 + test_expect_success 'arg after dashdash not interpreted as option' ' 258 + cat >expect <<-\EOF && 259 + -- 260 + --local-env-vars 261 + EOF 262 + git rev-parse -- --local-env-vars >actual && 263 + test_cmp expect actual 264 + ' 265 + 266 + test_expect_success 'arg after end-of-options not interpreted as option' ' 267 + test_must_fail git rev-parse --end-of-options --not-real -- 2>err && 268 + test_i18ngrep bad.revision.*--not-real err 269 + ' 270 + 271 + test_expect_success 'end-of-options still allows --' ' 272 + cat >expect <<-EOF && 273 + --end-of-options 274 + $(git rev-parse --verify HEAD) 275 + -- 276 + path 277 + EOF 278 + git rev-parse --end-of-options HEAD -- path >actual && 279 + test_cmp expect actual 280 + ' 281 + 257 282 test_done