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