name-rev: allow to specify a subpath for --refs option
authorNamhyung Kim <namhyung.kim@lge.com>
Tue, 18 Jun 2013 12:35:31 +0000 (21:35 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 18 Jun 2013 19:02:02 +0000 (12:02 -0700)
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>
Documentation/git-name-rev.txt
builtin/name-rev.c
index ad1d1468c9936d206701d379003177e7457c884e..6b0f1ba75fc98dedf7b940355274ad25d3b458c5 100644 (file)
@@ -25,7 +25,8 @@ OPTIONS
        Do not use branch names, but only tags to name the commits
 
 --refs=<pattern>::
-       Only use refs whose names match a given shell pattern.
+       Only use refs whose names match a given shell pattern.  The pattern
+       can be one of branch name, tag name or fully qualified ref name.
 
 --all::
        List all commits reachable from all refs
index 62382479749909d449b718fc2f3bef36906caa4b..87d485496fd5556cbd0f24793ed7e48f11e9b292 100644 (file)
@@ -82,6 +82,20 @@ static void name_rev(struct commit *commit,
        }
 }
 
+static int subpath_matches(const char *path, const char *filter)
+{
+       const char *subpath = path;
+
+       while (subpath) {
+               if (!fnmatch(filter, subpath, 0))
+                       return subpath - path;
+               subpath = strchr(subpath, '/');
+               if (subpath)
+                       subpath++;
+       }
+       return -1;
+}
+
 struct name_ref_data {
        int tags_only;
        int name_only;
@@ -92,13 +106,23 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
 {
        struct object *o = parse_object(sha1);
        struct name_ref_data *data = cb_data;
+       int can_abbreviate_output = data->tags_only && data->name_only;
        int deref = 0;
 
        if (data->tags_only && prefixcmp(path, "refs/tags/"))
                return 0;
 
-       if (data->ref_filter && fnmatch(data->ref_filter, path, 0))
-               return 0;
+       if (data->ref_filter) {
+               switch (subpath_matches(path, data->ref_filter)) {
+               case -1: /* did not match */
+                       return 0;
+               case 0:  /* matched fully */
+                       break;
+               default: /* matched subpath */
+                       can_abbreviate_output = 1;
+                       break;
+               }
+       }
 
        while (o && o->type == OBJ_TAG) {
                struct tag *t = (struct tag *) o;
@@ -110,12 +134,10 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
        if (o && o->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *)o;
 
-               if (!prefixcmp(path, "refs/heads/"))
+               if (can_abbreviate_output)
+                       path = shorten_unambiguous_ref(path, 0);
+               else if (!prefixcmp(path, "refs/heads/"))
                        path = path + 11;
-               else if (data->tags_only
-                   && data->name_only
-                   && !prefixcmp(path, "refs/tags/"))
-                       path = path + 10;
                else if (!prefixcmp(path, "refs/"))
                        path = path + 5;