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 <namhyung.kim@lge.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Namhyung Kim committed Jun 18, 2013 at 21:35 UTC 98c5c4ad01551b7764c9c8d8f67abfa9c5e595fe
2 files changed +31 -8
Documentation/git-name-rev.txt
+2 -1
@@ -25,7 +25,8 @@ OPTIONS
25 Do not use branch names, but only tags to name the commits
26
27 --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.
30
31 --all::
32 List all commits reachable from all refs
builtin/name-rev.c
+29 -7
@@ -82,6 +82,20 @@ copy_data:
82 }
83 }
84
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 +
99 struct name_ref_data {
100 int tags_only;
101 int name_only;
@@ -92,13 +106,23 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
106 {
107 struct object *o = parse_object(sha1);
108 struct name_ref_data *data = cb_data;
109 + int can_abbreviate_output = data->tags_only && data->name_only;
110 int deref = 0;
111
112 if (data->tags_only && prefixcmp(path, "refs/tags/"))
113 return 0;
114
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 + }
126
127 while (o && o->type == OBJ_TAG) {
128 struct tag *t = (struct tag *) o;
@@ -110,12 +134,10 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
134 if (o && o->type == OBJ_COMMIT) {
135 struct commit *commit = (struct commit *)o;
136
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/"))
140 path = path + 11;
115 - else if (data->tags_only
116 - && data->name_only
117 - && !prefixcmp(path, "refs/tags/"))
118 - path = path + 10;
141 else if (!prefixcmp(path, "refs/"))
142 path = path + 5;
143