Skip to content

Commit 290be66

Browse files
jacob-kellergitster
authored andcommitted
name-rev: extend --refs to accept multiple patterns
Teach git name-rev to take multiple --refs stored as a string list of patterns. The list of patterns will be matched inclusively, and each ref only needs to match one pattern to be included. A ref will only be excluded if it does not match any of the given patterns. Additionally, if any of the patterns would allow abbreviation, then we will abbreviate the ref, even if another pattern is more strict and would not have allowed abbreviation on its own. Add tests and documentation for this change. The tests expected output is dynamically generated. This is in order to avoid hard-coding a commit object name in the test results (as the expected output is to simply leave the commit object unnamed). Signed-off-by: Jacob Keller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4a68748 commit 290be66

File tree

3 files changed

+63
-13
lines changed

3 files changed

+63
-13
lines changed

Documentation/git-name-rev.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ OPTIONS
2626

2727
--refs=<pattern>::
2828
Only use refs whose names match a given shell pattern. The pattern
29-
can be one of branch name, tag name or fully qualified ref name.
29+
can be one of branch name, tag name or fully qualified ref name. If
30+
given multiple times, use refs whose names match any of the given shell
31+
patterns. Use `--no-refs` to clear any previous ref patterns given.
3032

3133
--all::
3234
List all commits reachable from all refs

builtin/name-rev.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
108108
struct name_ref_data {
109109
int tags_only;
110110
int name_only;
111-
const char *ref_filter;
111+
struct string_list ref_filters;
112112
};
113113

114114
static struct tip_table {
@@ -150,16 +150,38 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
150150
if (data->tags_only && !starts_with(path, "refs/tags/"))
151151
return 0;
152152

153-
if (data->ref_filter) {
154-
switch (subpath_matches(path, data->ref_filter)) {
155-
case -1: /* did not match */
156-
return 0;
157-
case 0: /* matched fully */
158-
break;
159-
default: /* matched subpath */
160-
can_abbreviate_output = 1;
161-
break;
153+
if (data->ref_filters.nr) {
154+
struct string_list_item *item;
155+
int matched = 0;
156+
157+
/* See if any of the patterns match. */
158+
for_each_string_list_item(item, &data->ref_filters) {
159+
/*
160+
* Check all patterns even after finding a match, so
161+
* that we can see if a match with a subpath exists.
162+
* When a user asked for 'refs/tags/v*' and 'v1.*',
163+
* both of which match, the user is showing her
164+
* willingness to accept a shortened output by having
165+
* the 'v1.*' in the acceptable refnames, so we
166+
* shouldn't stop when seeing 'refs/tags/v1.4' matches
167+
* 'refs/tags/v*'. We should show it as 'v1.4'.
168+
*/
169+
switch (subpath_matches(path, item->string)) {
170+
case -1: /* did not match */
171+
break;
172+
case 0: /* matched fully */
173+
matched = 1;
174+
break;
175+
default: /* matched subpath */
176+
matched = 1;
177+
can_abbreviate_output = 1;
178+
break;
179+
}
162180
}
181+
182+
/* If none of the patterns matched, stop now */
183+
if (!matched)
184+
return 0;
163185
}
164186

165187
add_to_tip_table(oid->hash, path, can_abbreviate_output);
@@ -306,11 +328,11 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
306328
{
307329
struct object_array revs = OBJECT_ARRAY_INIT;
308330
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
309-
struct name_ref_data data = { 0, 0, NULL };
331+
struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP };
310332
struct option opts[] = {
311333
OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
312334
OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
313-
OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
335+
OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
314336
N_("only use refs matching <pattern>")),
315337
OPT_GROUP(""),
316338
OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),

t/t6007-rev-list-cherry-pick-file.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,32 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '
9999
test_cmp actual.named expect
100100
'
101101

102+
test_expect_success 'name-rev multiple --refs combine inclusive' '
103+
git rev-list --left-right --cherry-pick F...E -- bar >actual &&
104+
git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
105+
<actual >actual.named &&
106+
test_cmp actual.named expect
107+
'
108+
109+
cat >expect <<EOF
110+
<tags/F
111+
EOF
112+
113+
test_expect_success 'name-rev --refs excludes non-matched patterns' '
114+
git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
115+
git rev-list --left-right --cherry-pick F...E -- bar >actual &&
116+
git name-rev --stdin --name-only --refs="*tags/F" \
117+
<actual >actual.named &&
118+
test_cmp actual.named expect
119+
'
120+
121+
test_expect_success 'name-rev --no-refs clears the refs list' '
122+
git rev-list --left-right --cherry-pick F...E -- bar >expect &&
123+
git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
124+
<expect >actual &&
125+
test_cmp actual expect
126+
'
127+
102128
cat >expect <<EOF
103129
+tags/F
104130
=tags/D

0 commit comments

Comments
 (0)