Skip to content

Commit 98c5c4a

Browse files
Namhyung Kimgitster
authored andcommitted
name-rev: allow to specify a subpath for --refs option
When an user wants to filter specific ref using the --refs option, the pattern needs to match the full ref, e.g. --refs=refs/tags/v1.*. It'd be convenient to specify a subpath of ref pattern. For example, --refs=origin/* can find refs/remotes/origin/master by searching the pattern against its substrings in turn: refs/remotes/origin/master remotes/origin/master origin/master If it finds a match in a subpath, unambigous part of the ref path will be removed in the output. Signed-off-by: Namhyung Kim <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent edca415 commit 98c5c4a

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

Documentation/git-name-rev.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ OPTIONS
2525
Do not use branch names, but only tags to name the commits
2626

2727
--refs=<pattern>::
28-
Only use refs whose names match a given shell pattern.
28+
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.
2930

3031
--all::
3132
List all commits reachable from all refs

builtin/name-rev.c

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ static void name_rev(struct commit *commit,
8282
}
8383
}
8484

85+
static int subpath_matches(const char *path, const char *filter)
86+
{
87+
const char *subpath = path;
88+
89+
while (subpath) {
90+
if (!fnmatch(filter, subpath, 0))
91+
return subpath - path;
92+
subpath = strchr(subpath, '/');
93+
if (subpath)
94+
subpath++;
95+
}
96+
return -1;
97+
}
98+
8599
struct name_ref_data {
86100
int tags_only;
87101
int name_only;
@@ -92,13 +106,23 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
92106
{
93107
struct object *o = parse_object(sha1);
94108
struct name_ref_data *data = cb_data;
109+
int can_abbreviate_output = data->tags_only && data->name_only;
95110
int deref = 0;
96111

97112
if (data->tags_only && prefixcmp(path, "refs/tags/"))
98113
return 0;
99114

100-
if (data->ref_filter && fnmatch(data->ref_filter, path, 0))
101-
return 0;
115+
if (data->ref_filter) {
116+
switch (subpath_matches(path, data->ref_filter)) {
117+
case -1: /* did not match */
118+
return 0;
119+
case 0: /* matched fully */
120+
break;
121+
default: /* matched subpath */
122+
can_abbreviate_output = 1;
123+
break;
124+
}
125+
}
102126

103127
while (o && o->type == OBJ_TAG) {
104128
struct tag *t = (struct tag *) o;
@@ -110,12 +134,10 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
110134
if (o && o->type == OBJ_COMMIT) {
111135
struct commit *commit = (struct commit *)o;
112136

113-
if (!prefixcmp(path, "refs/heads/"))
137+
if (can_abbreviate_output)
138+
path = shorten_unambiguous_ref(path, 0);
139+
else if (!prefixcmp(path, "refs/heads/"))
114140
path = path + 11;
115-
else if (data->tags_only
116-
&& data->name_only
117-
&& !prefixcmp(path, "refs/tags/"))
118-
path = path + 10;
119141
else if (!prefixcmp(path, "refs/"))
120142
path = path + 5;
121143

0 commit comments

Comments
 (0)