From: Andy Parkins Date: Tue, 21 Nov 2006 19:31:24 +0000 (+0000) Subject: Add support to git-branch to show local and remote branches X-Git-Tag: v1.5.0-rc0~233^2 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=bfcc921430423828233dadfe274802ae68900f6e;p=git.git Add support to git-branch to show local and remote branches Instead of storing a list of refnames in append_ref, a list of structures is created. Each of these stores the refname and a symbolic constant representing its type. The creation of the list is filtered based on a command line switch; no switch means "local branches only", "-r" means "remote branches only" (as they always did); but now "-a" means "local branches or remote branches". As a side effect, the list is now not global, but allocated in print_ref_list() where it used. Also a memory leak is plugged, the memory allocated during the list creation was never freed. It lays a groundwork to also display tags, but the command being 'git branch' it is not currently used. Signed-off-by: Andy Parkins Signed-off-by: Junio C Hamano --- diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index d43ef1dec..537676081 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -8,14 +8,16 @@ git-branch - List, create, or delete branches. SYNOPSIS -------- [verse] -'git-branch' [-r] +'git-branch' [-r] [-a] 'git-branch' [-l] [-f] [] 'git-branch' (-d | -D) ... DESCRIPTION ----------- -With no arguments given (or just `-r`) a list of available branches +With no arguments given a list of existing branches will be shown, the current branch will be highlighted with an asterisk. +Option `-r` causes the remote-tracking branches to be listed, +and option `-a` shows both. In its second form, a new branch named will be created. It will start out with a head equal to the one given as . @@ -45,7 +47,10 @@ OPTIONS a branch that already exists with the same name. -r:: - List only the "remote" branches. + List the remote-tracking branches. + +-a:: + List both remote-tracking branches and local branches. :: The name of the branch to create or delete. diff --git a/builtin-branch.c b/builtin-branch.c index 368b68ec9..22e3285a4 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -11,7 +11,7 @@ #include "builtin.h" static const char builtin_branch_usage[] = -"git-branch (-d | -D) | [-l] [-f] [] | [-r]"; +"git-branch (-d | -D) | [-l] [-f] [] | [-r] | [-a]"; static const char *head; @@ -79,46 +79,100 @@ static void delete_branches(int argc, const char **argv, int force) } } -static int ref_index, ref_alloc; -static char **ref_list; +#define REF_UNKNOWN_TYPE 0x00 +#define REF_LOCAL_BRANCH 0x01 +#define REF_REMOTE_BRANCH 0x02 +#define REF_TAG 0x04 -static int append_ref(const char *refname, const unsigned char *sha1, int flags, - void *cb_data) +struct ref_item { + char *name; + unsigned int kind; +}; + +struct ref_list { + int index, alloc; + struct ref_item *list; + int kinds; +}; + +static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { - if (ref_index >= ref_alloc) { - ref_alloc = alloc_nr(ref_alloc); - ref_list = xrealloc(ref_list, ref_alloc * sizeof(char *)); + struct ref_list *ref_list = (struct ref_list*)(cb_data); + struct ref_item *newitem; + int kind = REF_UNKNOWN_TYPE; + + /* Detect kind */ + if (!strncmp(refname, "refs/heads/", 11)) { + kind = REF_LOCAL_BRANCH; + refname += 11; + } else if (!strncmp(refname, "refs/remotes/", 13)) { + kind = REF_REMOTE_BRANCH; + refname += 13; + } else if (!strncmp(refname, "refs/tags/", 10)) { + kind = REF_TAG; + refname += 10; + } + + /* Don't add types the caller doesn't want */ + if ((kind & ref_list->kinds) == 0) + return 0; + + /* Resize buffer */ + if (ref_list->index >= ref_list->alloc) { + ref_list->alloc = alloc_nr(ref_list->alloc); + ref_list->list = xrealloc(ref_list->list, + ref_list->alloc * sizeof(struct ref_item)); } - ref_list[ref_index++] = xstrdup(refname); + /* Record the new item */ + newitem = &(ref_list->list[ref_list->index++]); + newitem->name = xstrdup(refname); + newitem->kind = kind; return 0; } +static void free_ref_list(struct ref_list *ref_list) +{ + int i; + + for (i = 0; i < ref_list->index; i++) + free(ref_list->list[i].name); + free(ref_list->list); +} + static int ref_cmp(const void *r1, const void *r2) { - return strcmp(*(char **)r1, *(char **)r2); + struct ref_item *c1 = (struct ref_item *)(r1); + struct ref_item *c2 = (struct ref_item *)(r2); + + if (c1->kind != c2->kind) + return c1->kind - c2->kind; + return strcmp(c1->name, c2->name); } -static void print_ref_list(int remote_only) +static void print_ref_list(int kinds) { int i; char c; + struct ref_list ref_list; - if (remote_only) - for_each_remote_ref(append_ref, NULL); - else - for_each_branch_ref(append_ref, NULL); + memset(&ref_list, 0, sizeof(ref_list)); + ref_list.kinds = kinds; + for_each_ref(append_ref, &ref_list); - qsort(ref_list, ref_index, sizeof(char *), ref_cmp); + qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); - for (i = 0; i < ref_index; i++) { + for (i = 0; i < ref_list.index; i++) { c = ' '; - if (!strcmp(ref_list[i], head)) + if (ref_list.list[i].kind == REF_LOCAL_BRANCH && + !strcmp(ref_list.list[i].name, head)) c = '*'; - printf("%c %s\n", c, ref_list[i]); + printf("%c %s\n", c, ref_list.list[i].name); } + + free_ref_list(&ref_list); } static void create_branch(const char *name, const char *start, @@ -160,8 +214,9 @@ static void create_branch(const char *name, const char *start, int cmd_branch(int argc, const char **argv, const char *prefix) { - int delete = 0, force_delete = 0, force_create = 0, remote_only = 0; + int delete = 0, force_delete = 0, force_create = 0; int reflog = 0; + int kinds = REF_LOCAL_BRANCH; int i; git_config(git_default_config); @@ -189,7 +244,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-r")) { - remote_only = 1; + kinds = REF_REMOTE_BRANCH; + continue; + } + if (!strcmp(arg, "-a")) { + kinds = REF_REMOTE_BRANCH | REF_LOCAL_BRANCH; continue; } if (!strcmp(arg, "-l")) { @@ -209,7 +268,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (delete) delete_branches(argc - i, argv + i, force_delete); else if (i == argc) - print_ref_list(remote_only); + print_ref_list(kinds); else if (i == argc - 1) create_branch(argv[i], head, force_create, reflog); else if (i == argc - 2)