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>
This commit is contained in:
Junio C Hamano 2005-12-04 15:58:50 -08:00
parent 7b9b4c452c
commit 287f860054
2 changed files with 84 additions and 15 deletions

View 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,

View 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];