зеркало из https://github.com/microsoft/git.git
Merge branch 'nd/for-each-ref-ignore-case'
"git branch --list" and friends learned "--ignore-case" option to optionally sort branches and tags case insensitively. * nd/for-each-ref-ignore-case: tag, branch, for-each-ref: add --ignore-case for sorting and filtering
This commit is contained in:
Коммит
73e494f862
|
@ -118,6 +118,10 @@ OPTIONS
|
|||
default to color output.
|
||||
Same as `--color=never`.
|
||||
|
||||
-i::
|
||||
--ignore-case::
|
||||
Sorting and filtering branches are case insensitive.
|
||||
|
||||
--column[=<options>]::
|
||||
--no-column::
|
||||
Display branch listing in columns. See configuration variable
|
||||
|
|
|
@ -79,6 +79,9 @@ OPTIONS
|
|||
Only list refs which contain the specified commit (HEAD if not
|
||||
specified).
|
||||
|
||||
--ignore-case::
|
||||
Sorting and filtering refs are case insensitive.
|
||||
|
||||
FIELD NAMES
|
||||
-----------
|
||||
|
||||
|
|
|
@ -108,6 +108,10 @@ OPTIONS
|
|||
variable if it exists, or lexicographic order otherwise. See
|
||||
linkgit:git-config[1].
|
||||
|
||||
-i::
|
||||
--ignore-case::
|
||||
Sorting and filtering tags are case insensitive.
|
||||
|
||||
--column[=<options>]::
|
||||
--no-column::
|
||||
Display tag listing in columns. See configuration variable
|
||||
|
|
|
@ -512,15 +512,6 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
|
|||
if (filter->verbose)
|
||||
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
|
||||
|
||||
/*
|
||||
* If no sorting parameter is given then we default to sorting
|
||||
* by 'refname'. This would give us an alphabetically sorted
|
||||
* array with the 'HEAD' ref at the beginning followed by
|
||||
* local branches 'refs/heads/...' and finally remote-tacking
|
||||
* branches 'refs/remotes/...'.
|
||||
*/
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
ref_array_sort(sorting, &array);
|
||||
|
||||
for (i = 0; i < array.nr; i++)
|
||||
|
@ -645,6 +636,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
|||
const char *new_upstream = NULL;
|
||||
enum branch_track track;
|
||||
struct ref_filter filter;
|
||||
int icase = 0;
|
||||
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
|
||||
|
||||
struct option options[] = {
|
||||
|
@ -686,6 +678,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
|||
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
|
||||
N_("print only branches of the object"), 0, parse_opt_object_name
|
||||
},
|
||||
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
|
@ -723,6 +716,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if (filter.abbrev == -1)
|
||||
filter.abbrev = DEFAULT_ABBREV;
|
||||
filter.ignore_case = icase;
|
||||
|
||||
finalize_colopts(&colopts, -1);
|
||||
if (filter.verbose) {
|
||||
if (explicitly_enable_column(colopts))
|
||||
|
@ -744,6 +739,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
|||
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
|
||||
filter.kind |= FILTER_REFS_DETACHED_HEAD;
|
||||
filter.name_patterns = argv;
|
||||
/*
|
||||
* If no sorting parameter is given then we default to sorting
|
||||
* by 'refname'. This would give us an alphabetically sorted
|
||||
* array with the 'HEAD' ref at the beginning followed by
|
||||
* local branches 'refs/heads/...' and finally remote-tacking
|
||||
* branches 'refs/remotes/...'.
|
||||
*/
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
sorting->ignore_case = icase;
|
||||
print_ref_list(&filter, sorting);
|
||||
print_columns(&output, colopts, NULL);
|
||||
string_list_clear(&output, 0);
|
||||
|
|
|
@ -18,7 +18,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
|||
int i;
|
||||
const char *format = "%(objectname) %(objecttype)\t%(refname)";
|
||||
struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
|
||||
int maxcount = 0, quote_style = 0;
|
||||
int maxcount = 0, quote_style = 0, icase = 0;
|
||||
struct ref_array array;
|
||||
struct ref_filter filter;
|
||||
|
||||
|
@ -43,6 +43,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
|||
OPT_MERGED(&filter, N_("print only refs that are merged")),
|
||||
OPT_NO_MERGED(&filter, N_("print only refs that are not merged")),
|
||||
OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")),
|
||||
OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
|
@ -63,6 +64,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
|||
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
sorting->ignore_case = icase;
|
||||
filter.ignore_case = icase;
|
||||
|
||||
/* for warn_ambiguous_refs */
|
||||
git_config(git_default_config, NULL);
|
||||
|
|
|
@ -335,6 +335,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||
struct ref_filter filter;
|
||||
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
|
||||
const char *format = NULL;
|
||||
int icase = 0;
|
||||
struct option options[] = {
|
||||
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
|
||||
{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"),
|
||||
|
@ -370,6 +371,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||
N_("print only tags of the object"), 0, parse_opt_object_name
|
||||
},
|
||||
OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
|
||||
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -401,6 +403,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
|||
}
|
||||
if (!sorting)
|
||||
sorting = ref_default_sorting();
|
||||
sorting->ignore_case = icase;
|
||||
filter.ignore_case = icase;
|
||||
if (cmdmode == 'l') {
|
||||
int ret;
|
||||
if (column_active(colopts)) {
|
||||
|
|
28
ref-filter.c
28
ref-filter.c
|
@ -1231,8 +1231,14 @@ static int commit_contains(struct ref_filter *filter, struct commit *commit)
|
|||
* matches a pattern "refs/heads/mas") or a wildcard (e.g. the same ref
|
||||
* matches "refs/heads/mas*", too).
|
||||
*/
|
||||
static int match_pattern(const char **patterns, const char *refname)
|
||||
static int match_pattern(const struct ref_filter *filter, const char *refname)
|
||||
{
|
||||
const char **patterns = filter->name_patterns;
|
||||
unsigned flags = 0;
|
||||
|
||||
if (filter->ignore_case)
|
||||
flags |= WM_CASEFOLD;
|
||||
|
||||
/*
|
||||
* When no '--format' option is given we need to skip the prefix
|
||||
* for matching refs of tags and branches.
|
||||
|
@ -1243,7 +1249,7 @@ static int match_pattern(const char **patterns, const char *refname)
|
|||
skip_prefix(refname, "refs/", &refname));
|
||||
|
||||
for (; *patterns; patterns++) {
|
||||
if (!wildmatch(*patterns, refname, 0, NULL))
|
||||
if (!wildmatch(*patterns, refname, flags, NULL))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1255,9 +1261,15 @@ static int match_pattern(const char **patterns, const char *refname)
|
|||
* matches a pattern "refs/heads/" but not "refs/heads/m") or a
|
||||
* wildcard (e.g. the same ref matches "refs/heads/m*", too).
|
||||
*/
|
||||
static int match_name_as_path(const char **pattern, const char *refname)
|
||||
static int match_name_as_path(const struct ref_filter *filter, const char *refname)
|
||||
{
|
||||
const char **pattern = filter->name_patterns;
|
||||
int namelen = strlen(refname);
|
||||
unsigned flags = WM_PATHNAME;
|
||||
|
||||
if (filter->ignore_case)
|
||||
flags |= WM_CASEFOLD;
|
||||
|
||||
for (; *pattern; pattern++) {
|
||||
const char *p = *pattern;
|
||||
int plen = strlen(p);
|
||||
|
@ -1280,8 +1292,8 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
|
|||
if (!*filter->name_patterns)
|
||||
return 1; /* No pattern always matches */
|
||||
if (filter->match_as_path)
|
||||
return match_name_as_path(filter->name_patterns, refname);
|
||||
return match_pattern(filter->name_patterns, refname);
|
||||
return match_name_as_path(filter, refname);
|
||||
return match_pattern(filter, refname);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1536,18 +1548,20 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
|
|||
struct atom_value *va, *vb;
|
||||
int cmp;
|
||||
cmp_type cmp_type = used_atom[s->atom].type;
|
||||
int (*cmp_fn)(const char *, const char *);
|
||||
|
||||
get_ref_atom_value(a, s->atom, &va);
|
||||
get_ref_atom_value(b, s->atom, &vb);
|
||||
cmp_fn = s->ignore_case ? strcasecmp : strcmp;
|
||||
if (s->version)
|
||||
cmp = versioncmp(va->s, vb->s);
|
||||
else if (cmp_type == FIELD_STR)
|
||||
cmp = strcmp(va->s, vb->s);
|
||||
cmp = cmp_fn(va->s, vb->s);
|
||||
else {
|
||||
if (va->ul < vb->ul)
|
||||
cmp = -1;
|
||||
else if (va->ul == vb->ul)
|
||||
cmp = strcmp(a->refname, b->refname);
|
||||
cmp = cmp_fn(a->refname, b->refname);
|
||||
else
|
||||
cmp = 1;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ struct ref_sorting {
|
|||
struct ref_sorting *next;
|
||||
int atom; /* index into used_atom array (internal) */
|
||||
unsigned reverse : 1,
|
||||
ignore_case : 1,
|
||||
version : 1;
|
||||
};
|
||||
|
||||
|
@ -62,6 +63,7 @@ struct ref_filter {
|
|||
|
||||
unsigned int with_commit_tag_algo : 1,
|
||||
match_as_path : 1,
|
||||
ignore_case : 1,
|
||||
detached : 1;
|
||||
unsigned int kind,
|
||||
lines;
|
||||
|
|
|
@ -89,6 +89,11 @@ test_expect_success 'git branch --list -v pattern shows branch summaries' '
|
|||
awk "{print \$NF}" <tmp >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
test_expect_success 'git branch --ignore-case --list -v pattern shows branch summaries' '
|
||||
git branch --list --ignore-case -v BRANCH* >tmp &&
|
||||
awk "{print \$NF}" <tmp >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'git branch -v pattern does not show branch summaries' '
|
||||
test_must_fail git branch -v branch*
|
||||
|
@ -196,4 +201,28 @@ test_expect_success 'local-branch symrefs shortened properly' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'sort branches, ignore case' '
|
||||
(
|
||||
git init sort-icase &&
|
||||
cd sort-icase &&
|
||||
test_commit initial &&
|
||||
git branch branch-one &&
|
||||
git branch BRANCH-two &&
|
||||
git branch --list | awk "{print \$NF}" >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
BRANCH-two
|
||||
branch-one
|
||||
master
|
||||
EOF
|
||||
test_cmp expected actual &&
|
||||
git branch --list -i | awk "{print \$NF}" >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
branch-one
|
||||
BRANCH-two
|
||||
master
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -27,6 +27,30 @@ test_expect_success 'listing all tags in an empty tree should output nothing' '
|
|||
test $(git tag | wc -l) -eq 0
|
||||
'
|
||||
|
||||
test_expect_success 'sort tags, ignore case' '
|
||||
(
|
||||
git init sort &&
|
||||
cd sort &&
|
||||
test_commit initial &&
|
||||
git tag tag-one &&
|
||||
git tag TAG-two &&
|
||||
git tag -l >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
TAG-two
|
||||
initial
|
||||
tag-one
|
||||
EOF
|
||||
test_cmp expected actual &&
|
||||
git tag -l -i >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
initial
|
||||
tag-one
|
||||
TAG-two
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'looking for a tag in an empty tree should fail' \
|
||||
'! (tag_exists mytag)'
|
||||
|
||||
|
@ -81,6 +105,9 @@ test_expect_success 'listing all tags if one exists should output that tag' '
|
|||
test_expect_success 'listing a tag using a matching pattern should succeed' \
|
||||
'git tag -l mytag'
|
||||
|
||||
test_expect_success 'listing a tag with --ignore-case' \
|
||||
'test $(git tag -l --ignore-case MYTAG) = mytag'
|
||||
|
||||
test_expect_success \
|
||||
'listing a tag using a matching pattern should output that tag' \
|
||||
'test $(git tag -l mytag) = mytag'
|
||||
|
|
Загрузка…
Ссылка в новой задаче