show-branch: allow glob pattern to name branches to show.
authorJunio C Hamano <junkio@cox.net>
Sun, 4 Dec 2005 23:58:50 +0000 (15:58 -0800)
committerJunio C Hamano <junkio@cox.net>
Mon, 5 Dec 2005 00:06:35 +0000 (16:06 -0800)
With this, you can say "git-show-branch topic/* master" to show
all the topic branches you have under .git/refs/heads/topic/ and
your master branch.  Another example is "git-show-branch --list
v1.0*" to show all the v1.0 tags.  You can disambiguate by
saying "heads/topic/*" to show only topic branches if you have
tags under .git/refs/tags/topic/ as well.

Signed-off-by: Junio C Hamano <junkio@cox.net>
Documentation/git-show-branch.txt
show-branch.c

index c6c97b2..304101d 100644 (file)
@@ -7,18 +7,29 @@ git-show-branch - Show branches and their commits.
 
 SYNOPSIS
 --------
-'git-show-branch [--all] [--heads] [--tags] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] <reference>...'
+'git-show-branch [--all] [--heads] [--tags] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [<rev> | <glob>]...'
 
 DESCRIPTION
 -----------
-Shows the head commits from the named <reference> (or all refs under
-$GIT_DIR/refs/heads), and displays concise list of commit logs
-to show their relationship semi-visually.
+
+Shows the commit ancestry graph starting from the commits named
+with <rev>s or <globs>s (or all refs under $GIT_DIR/refs/heads
+and/or $GIT_DIR/refs/tags) semi-visually.
+
+It cannot show more than 29 branches and commits at a time.
+
 
 OPTIONS
 -------
-<reference>::
-       Name of the reference under $GIT_DIR/refs/.
+<rev>::
+       Arbitrary extended SHA1 expression (see `git-rev-parse`)
+       that typically names a branch HEAD or a tag.
+
+<glob>::
+       A glob pattern that matches branch or tag names under
+       $GIT_DIR/refs.  For example, if you have many topic
+       branches under $GIT_DIR/refs/heads/topic, giving
+       `topic/*` would show all of them.
 
 --all --heads --tags::
        Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
index d8808ee..bff690d 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdlib.h>
+#include <fnmatch.h>
 #include "cache.h"
 #include "commit.h"
 #include "refs.h"
@@ -332,6 +333,39 @@ static int append_tag_ref(const char *refname, const unsigned char *sha1)
        return append_ref(refname + 5, sha1);
 }
 
+static const char *match_ref_pattern = NULL;
+static int match_ref_slash = 0;
+static int count_slash(const char *s)
+{
+       int cnt = 0;
+       while (*s)
+               if (*s++ == '/')
+                       cnt++;
+       return cnt;
+}
+
+static int append_matching_ref(const char *refname, const unsigned char *sha1)
+{
+       /* we want to allow pattern hold/<asterisk> to show all
+        * branches under refs/heads/hold/, and v0.99.9? to show
+        * refs/tags/v0.99.9a and friends.
+        */
+       const char *tail;
+       int slash = count_slash(refname);
+       for (tail = refname; *tail && match_ref_slash < slash; )
+               if (*tail++ == '/')
+                       slash--;
+       if (!*tail)
+               return 0;
+       if (fnmatch(match_ref_pattern, tail, 0))
+               return 0;
+       if (!strncmp("refs/heads/", refname, 11))
+               return append_head_ref(refname, sha1);
+       if (!strncmp("refs/tags/", refname, 10))
+               return append_tag_ref(refname, sha1);
+       return append_ref(refname, sha1);
+}
+
 static void snarf_refs(int head, int tag)
 {
        if (head) {
@@ -400,6 +434,27 @@ static int show_independent(struct commit **rev,
        return 0;
 }
 
+static void append_one_rev(const char *av)
+{
+       unsigned char revkey[20];
+       if (!get_sha1(av, revkey)) {
+               append_ref(av, revkey);
+               return;
+       }
+       if (strchr(av, '*') || strchr(av, '?')) {
+               /* glob style match */
+               int saved_matches = ref_name_cnt;
+               match_ref_pattern = av;
+               match_ref_slash = count_slash(av);
+               for_each_ref(append_matching_ref);
+               if (saved_matches == ref_name_cnt &&
+                   ref_name_cnt < MAX_REVS)
+                       error("no matching refs with %s", av);
+               return;
+       }
+       die("bad sha1 reference %s", av);
+}
+
 int main(int ac, char **av)
 {
        struct commit *rev[MAX_REVS], *commit;
@@ -458,17 +513,20 @@ int main(int ac, char **av)
        if (all_heads + all_tags)
                snarf_refs(all_heads, all_tags);
 
-       while (0 < ac) {
-               unsigned char revkey[20];
-               if (get_sha1(*av, revkey))
-                       die("bad sha1 reference %s", *av);
-               append_ref(*av, revkey);
-               ac--; av++;
+       if (ac) {
+               while (0 < ac) {
+                       append_one_rev(*av);
+                       ac--; av++;
+               }
        }
-
-       /* If still no revs, then add heads */
-       if (!ref_name_cnt)
+       else {
+               /* If no revs given, then add heads */
                snarf_refs(1, 0);
+       }
+       if (!ref_name_cnt) {
+               fprintf(stderr, "No revs to be shown.\n");
+               exit(0);
+       }
 
        for (num_rev = 0; ref_name[num_rev]; num_rev++) {
                unsigned char revkey[20];