tag: accept multiple patterns for --list

Until now, "git tag -l foo* bar*" would silently ignore the second argument, showing only refs starting with "foo". It's not just unfriendly not to take a second pattern; we actually generated subtly wrong results (from the user's perspective) because some of the requested tags were omitted. This patch allows an arbitrary number of patterns on the command line; if any of them matches, the ref is shown. While we're tweaking the documentation, let's also make it clear that the pattern is fnmatch. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jun 20, 2011 at 12:59 UTC 588d0e834b244565863fa80e6c48c20e0db9b62f
3 files changed +28 -12
Documentation/git-tag.txt
+6 -3
@@ -12,7 +12,7 @@ SYNOPSIS
12 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
13 <tagname> [<commit> | <object>]
14 'git tag' -d <tagname>...
15 -'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>]
15 +'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...]
16 'git tag' -v <tagname>...
17
18 DESCRIPTION
@@ -69,8 +69,11 @@ OPTIONS
69 If the tag is not annotated, the commit message is displayed instead.
70
71 -l <pattern>::
72 - List tags with names that match the given pattern (or all if no pattern is given).
73 - Typing "git tag" without arguments, also lists all tags.
72 + List tags with names that match the given pattern (or all if no
73 + pattern is given). Running "git tag" without arguments also
74 + lists all tags. The pattern is a shell wildcard (i.e., matched
75 + using fnmatch(3)). Multiple patterns may be given; if any of
76 + them matches, the tag is shown.
77
78 --contains <commit>::
79 Only list tags which contain the specified commit.
builtin/tag.c
+17 -9
@@ -16,7 +16,7 @@
16 static const char * const git_tag_usage[] = {
17 "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
18 "git tag -d <tagname>...",
19 - "git tag -l [-n[<num>]] [<pattern>]",
19 + "git tag -l [-n[<num>]] [<pattern>...]",
20 "git tag -v <tagname>...",
21 NULL
22 };
@@ -24,17 +24,28 @@ static const char * const git_tag_usage[] = {
24 static char signingkey[1000];
25
26 struct tag_filter {
27 - const char *pattern;
27 + const char **patterns;
28 int lines;
29 struct commit_list *with_commit;
30 };
31
32 +static int match_pattern(const char **patterns, const char *ref)
33 +{
34 + /* no pattern means match everything */
35 + if (!*patterns)
36 + return 1;
37 + for (; *patterns; patterns++)
38 + if (!fnmatch(*patterns, ref, 0))
39 + return 1;
40 + return 0;
41 +}
42 +
43 static int show_reference(const char *refname, const unsigned char *sha1,
44 int flag, void *cb_data)
45 {
46 struct tag_filter *filter = cb_data;
47
37 - if (!fnmatch(filter->pattern, refname, 0)) {
48 + if (match_pattern(filter->patterns, refname)) {
49 int i;
50 unsigned long size;
51 enum object_type type;
@@ -88,15 +99,12 @@ static int show_reference(const char *refname, const unsigned char *sha1,
99 return 0;
100 }
101
91 -static int list_tags(const char *pattern, int lines,
102 +static int list_tags(const char **patterns, int lines,
103 struct commit_list *with_commit)
104 {
105 struct tag_filter filter;
106
96 - if (pattern == NULL)
97 - pattern = "*";
98 -
99 - filter.pattern = pattern;
107 + filter.patterns = patterns;
108 filter.lines = lines;
109 filter.with_commit = with_commit;
110
@@ -414,7 +422,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
422 if (list + delete + verify > 1)
423 usage_with_options(git_tag_usage, options);
424 if (list)
417 - return list_tags(argv[0], lines == -1 ? 0 : lines,
425 + return list_tags(argv, lines == -1 ? 0 : lines,
426 with_commit);
427 if (lines != -1)
428 die(_("-n option is only allowed with -l."));
t/t7004-tag.sh
+5
@@ -257,6 +257,11 @@ test_expect_success \
257 test_cmp expect actual
258 '
259
260 +test_expect_success 'tag -l can accept multiple patterns' '
261 + git tag -l "v1*" "v0*" >actual &&
262 + test_cmp expect actual
263 +'
264 +
265 # creating and verifying lightweight tags:
266
267 test_expect_success \