summaryrefslogtreecommitdiff
path: root/show-branch.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2005-12-04 15:58:50 -0800
committerJunio C Hamano <junkio@cox.net>2005-12-04 16:06:35 -0800
commit287f860054345505e4f737466279efa6c3ff04b5 (patch)
tree240563de5898adcf52be5ea7b70839ba5db67ab3 /show-branch.c
parent7b9b4c452c793d0f8e3ff9f0b7fe526448fc314a (diff)
downloadgit-287f860054345505e4f737466279efa6c3ff04b5.tar.gz
show-branch: allow glob pattern to name branches to show.
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>
Diffstat (limited to 'show-branch.c')
-rw-r--r--show-branch.c76
1 files changed, 67 insertions, 9 deletions
diff --git a/show-branch.c b/show-branch.c
index d8808eefce..bff690d988 100644
--- a/show-branch.c
+++ b/show-branch.c
@@ -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];