tag: implicitly supply --list given another list-like option

Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ævar Arnfjörð Bjarmason committed Mar 24, 2017 at 18:40 UTC 6a338149f623f493525324bc0f8d7bb9257cb840
3 files changed +73 -17
Documentation/git-tag.txt
+11 -6
@@ -82,10 +82,11 @@ OPTIONS
82
83 -n<num>::
84 <num> specifies how many lines from the annotation, if any,
85 - are printed when using -l.
86 - The default is not to print any annotation lines.
87 - If no number is given to `-n`, only the first line is printed.
88 - If the tag is not annotated, the commit message is displayed instead.
85 + are printed when using -l. Implies `--list`.
86 ++
87 +The default is not to print any annotation lines.
88 +If no number is given to `-n`, only the first line is printed.
89 +If the tag is not annotated, the commit message is displayed instead.
90
91 -l::
92 --list::
@@ -95,6 +96,10 @@ OPTIONS
96 Running "git tag" without arguments also lists all tags. The pattern
97 is a shell wildcard (i.e., matched using fnmatch(3)). Multiple
98 patterns may be given; if any of them matches, the tag is shown.
99 ++
100 +This option is implicitly supplied if any other list-like option such
101 +as `--contains` is provided. See the documentation for each of those
102 +options for details.
103
104 --sort=<key>::
105 Sort based on the key given. Prefix `-` to sort in
@@ -123,7 +128,7 @@ This option is only applicable when listing tags without annotation lines.
128
129 --contains [<commit>]::
130 Only list tags which contain the specified commit (HEAD if not
126 - specified).
131 + specified). Implies `--list`.
132
133 --merged [<commit>]::
134 Only list tags whose commits are reachable from the specified
@@ -134,7 +139,7 @@ This option is only applicable when listing tags without annotation lines.
139 commit (`HEAD` if not specified), incompatible with `--merged`.
140
141 --points-at <object>::
137 - Only list tags of the given object.
142 + Only list tags of the given object. Implies `--list`.
143
144 -m <msg>::
145 --message=<msg>::
builtin/tag.c
+12 -6
@@ -454,8 +454,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
454 }
455 create_tag_object = (opt.sign || annotate || msg.given || msgfile);
456
457 - if (argc == 0 && !cmdmode)
458 - cmdmode = 'l';
457 + if (!cmdmode) {
458 + if (argc == 0)
459 + cmdmode = 'l';
460 + else if (filter.with_commit ||
461 + filter.points_at.nr || filter.merge_commit ||
462 + filter.lines != -1)
463 + cmdmode = 'l';
464 + }
465
466 if ((create_tag_object || force) && (cmdmode != 0))
467 usage_with_options(git_tag_usage, options);
@@ -485,13 +491,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
491 return ret;
492 }
493 if (filter.lines != -1)
488 - die(_("-n option is only allowed with -l."));
494 + die(_("-n option is only allowed in list mode"));
495 if (filter.with_commit)
490 - die(_("--contains option is only allowed with -l."));
496 + die(_("--contains option is only allowed in list mode"));
497 if (filter.points_at.nr)
492 - die(_("--points-at option is only allowed with -l."));
498 + die(_("--points-at option is only allowed in list mode"));
499 if (filter.merge_commit)
494 - die(_("--merged and --no-merged option are only allowed with -l"));
500 + die(_("--merged and --no-merged options are only allowed in list mode"));
501 if (cmdmode == 'd')
502 return for_each_tag_name(argv, delete_tag, NULL);
503 if (cmdmode == 'v') {
t/t7004-tag.sh
+50 -5
@@ -643,6 +643,11 @@ test_expect_success \
643 git tag -n0 -l tag-one-line >actual &&
644 test_cmp expect actual &&
645
646 + git tag -n0 | grep "^tag-one-line" >actual &&
647 + test_cmp expect actual &&
648 + git tag -n0 tag-one-line >actual &&
649 + test_cmp expect actual &&
650 +
651 echo "tag-one-line A msg" >expect &&
652 git tag -n1 -l | grep "^tag-one-line" >actual &&
653 test_cmp expect actual &&
@@ -656,6 +661,17 @@ test_expect_success \
661 test_cmp expect actual
662 '
663
664 +test_expect_success 'The -n 100 invocation means -n --list 100, not -n100' '
665 + >expect &&
666 + git tag -n 100 >actual &&
667 + test_cmp expect actual &&
668 +
669 + git tag -m "A msg" 100 &&
670 + echo "100 A msg" >expect &&
671 + git tag -n 100 >actual &&
672 + test_cmp expect actual
673 +'
674 +
675 test_expect_success \
676 'listing the zero-lines message of a non-signed tag should succeed' '
677 git tag -m "" tag-zero-lines &&
@@ -1476,6 +1492,11 @@ test_expect_success 'checking that initial commit is in all tags' "
1492 test_cmp expected actual
1493 "
1494
1495 +test_expect_success 'checking that --contains can be used in non-list mode' '
1496 + git tag --contains $hash1 v* >actual &&
1497 + test_cmp expected actual
1498 +'
1499 +
1500 # mixing modes and options:
1501
1502 test_expect_success 'mixing incompatibles modes and options is forbidden' '
@@ -1496,7 +1517,6 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '
1517 test_must_fail git tag -l -v &&
1518 test_must_fail git tag -l -d &&
1519 test_must_fail git tag -l -v -d &&
1499 - test_must_fail git tag -n 100 &&
1520 test_must_fail git tag -n 100 -v &&
1521 test_must_fail git tag -l -m msg &&
1522 test_must_fail git tag -l -F some file &&
@@ -1505,10 +1525,25 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '
1525 test_must_fail git tag --contains tag-blob
1526 '
1527
1528 +for option in --contains --merged --no-merged --points-at
1529 +do
1530 + test_expect_success "mixing incompatible modes with $option is forbidden" "
1531 + test_must_fail git tag -d $option HEAD &&
1532 + test_must_fail git tag -d $option HEAD some-tag &&
1533 + test_must_fail git tag -v $option HEAD
1534 + "
1535 + test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" "
1536 + git tag -n $option HEAD HEAD &&
1537 + git tag $option HEAD HEAD
1538 + "
1539 +done
1540 +
1541 # check points-at
1542
1510 -test_expect_success '--points-at cannot be used in non-list mode' '
1511 - test_must_fail git tag --points-at=v4.0 foo
1543 +test_expect_success '--points-at can be used in non-list mode' '
1544 + echo v4.0 >expect &&
1545 + git tag --points-at=v4.0 "v*" >actual &&
1546 + test_cmp expect actual
1547 '
1548
1549 test_expect_success '--points-at finds lightweight tags' '
@@ -1785,8 +1820,13 @@ test_expect_success 'setup --merged test tags' '
1820 git tag mergetest-3 HEAD
1821 '
1822
1788 -test_expect_success '--merged cannot be used in non-list mode' '
1789 - test_must_fail git tag --merged=mergetest-2 foo
1823 +test_expect_success '--merged can be used in non-list mode' '
1824 + cat >expect <<-\EOF &&
1825 + mergetest-1
1826 + mergetest-2
1827 + EOF
1828 + git tag --merged=mergetest-2 "mergetest*" >actual &&
1829 + test_cmp expect actual
1830 '
1831
1832 test_expect_success '--merged is incompatible with --no-merged' '
@@ -1810,6 +1850,11 @@ test_expect_success '--no-merged show unmerged tags' '
1850 test_cmp expect actual
1851 '
1852
1853 +test_expect_success '--no-merged can be used in non-list mode' '
1854 + git tag --no-merged=mergetest-2 mergetest-* >actual &&
1855 + test_cmp expect actual
1856 +'
1857 +
1858 test_expect_success 'ambiguous branch/tags not marked' '
1859 git tag ambiguous &&
1860 git branch ambiguous &&