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>
This commit is contained in:
Jeff King 2011-06-20 12:59:28 -04:00 committed by Junio C Hamano
parent daab4eeafa
commit 588d0e834b
3 changed files with 28 additions and 12 deletions

View File

@ -12,7 +12,7 @@ SYNOPSIS
'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
<tagname> [<commit> | <object>] <tagname> [<commit> | <object>]
'git tag' -d <tagname>... 'git tag' -d <tagname>...
'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>] 'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...]
'git tag' -v <tagname>... 'git tag' -v <tagname>...
DESCRIPTION DESCRIPTION
@ -69,8 +69,11 @@ OPTIONS
If the tag is not annotated, the commit message is displayed instead. If the tag is not annotated, the commit message is displayed instead.
-l <pattern>:: -l <pattern>::
List tags with names that match the given pattern (or all if no pattern is given). List tags with names that match the given pattern (or all if no
Typing "git tag" without arguments, also lists all tags. pattern is given). Running "git tag" without arguments also
lists all tags. The pattern is a shell wildcard (i.e., matched
using fnmatch(3)). Multiple patterns may be given; if any of
them matches, the tag is shown.
--contains <commit>:: --contains <commit>::
Only list tags which contain the specified commit. Only list tags which contain the specified commit.

View File

@ -16,7 +16,7 @@
static const char * const git_tag_usage[] = { static const char * const git_tag_usage[] = {
"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]", "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
"git tag -d <tagname>...", "git tag -d <tagname>...",
"git tag -l [-n[<num>]] [<pattern>]", "git tag -l [-n[<num>]] [<pattern>...]",
"git tag -v <tagname>...", "git tag -v <tagname>...",
NULL NULL
}; };
@ -24,17 +24,28 @@ static const char * const git_tag_usage[] = {
static char signingkey[1000]; static char signingkey[1000];
struct tag_filter { struct tag_filter {
const char *pattern; const char **patterns;
int lines; int lines;
struct commit_list *with_commit; struct commit_list *with_commit;
}; };
static int match_pattern(const char **patterns, const char *ref)
{
/* no pattern means match everything */
if (!*patterns)
return 1;
for (; *patterns; patterns++)
if (!fnmatch(*patterns, ref, 0))
return 1;
return 0;
}
static int show_reference(const char *refname, const unsigned char *sha1, static int show_reference(const char *refname, const unsigned char *sha1,
int flag, void *cb_data) int flag, void *cb_data)
{ {
struct tag_filter *filter = cb_data; struct tag_filter *filter = cb_data;
if (!fnmatch(filter->pattern, refname, 0)) { if (match_pattern(filter->patterns, refname)) {
int i; int i;
unsigned long size; unsigned long size;
enum object_type type; enum object_type type;
@ -88,15 +99,12 @@ static int show_reference(const char *refname, const unsigned char *sha1,
return 0; return 0;
} }
static int list_tags(const char *pattern, int lines, static int list_tags(const char **patterns, int lines,
struct commit_list *with_commit) struct commit_list *with_commit)
{ {
struct tag_filter filter; struct tag_filter filter;
if (pattern == NULL) filter.patterns = patterns;
pattern = "*";
filter.pattern = pattern;
filter.lines = lines; filter.lines = lines;
filter.with_commit = with_commit; filter.with_commit = with_commit;
@ -414,7 +422,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (list + delete + verify > 1) if (list + delete + verify > 1)
usage_with_options(git_tag_usage, options); usage_with_options(git_tag_usage, options);
if (list) if (list)
return list_tags(argv[0], lines == -1 ? 0 : lines, return list_tags(argv, lines == -1 ? 0 : lines,
with_commit); with_commit);
if (lines != -1) if (lines != -1)
die(_("-n option is only allowed with -l.")); die(_("-n option is only allowed with -l."));

View File

@ -257,6 +257,11 @@ test_expect_success \
test_cmp expect actual test_cmp expect actual
' '
test_expect_success 'tag -l can accept multiple patterns' '
git tag -l "v1*" "v0*" >actual &&
test_cmp expect actual
'
# creating and verifying lightweight tags: # creating and verifying lightweight tags:
test_expect_success \ test_expect_success \