X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=builtin-branch.c;h=515330c155a8e54c72fd02ea74e30be10b852490;hb=aa1cef54a2bcc5350df7efe1d1745725c46bf2e3;hp=22e3285a4ccf42f1f5a679eb209925bb03419d0f;hpb=9919b5ea8cfcd709b72e731af2ae62e011954ed9;p=git.git diff --git a/builtin-branch.c b/builtin-branch.c index 22e3285a4..515330c15 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -6,17 +6,70 @@ */ #include "cache.h" +#include "color.h" #include "refs.h" #include "commit.h" #include "builtin.h" static const char builtin_branch_usage[] = -"git-branch (-d | -D) | [-l] [-f] [] | [-r] | [-a]"; + "git-branch (-d | -D) | [-l] [-f] [] | (-m | -M) [] | [-r | -a] [-v [--abbrev=]]"; static const char *head; static unsigned char head_sha1[20]; +static int branch_use_color; +static char branch_colors[][COLOR_MAXLEN] = { + "\033[m", /* reset */ + "", /* PLAIN (normal) */ + "\033[31m", /* REMOTE (red) */ + "", /* LOCAL (normal) */ + "\033[32m", /* CURRENT (green) */ +}; +enum color_branch { + COLOR_BRANCH_RESET = 0, + COLOR_BRANCH_PLAIN = 1, + COLOR_BRANCH_REMOTE = 2, + COLOR_BRANCH_LOCAL = 3, + COLOR_BRANCH_CURRENT = 4, +}; + +static int parse_branch_color_slot(const char *var, int ofs) +{ + if (!strcasecmp(var+ofs, "plain")) + return COLOR_BRANCH_PLAIN; + if (!strcasecmp(var+ofs, "reset")) + return COLOR_BRANCH_RESET; + if (!strcasecmp(var+ofs, "remote")) + return COLOR_BRANCH_REMOTE; + if (!strcasecmp(var+ofs, "local")) + return COLOR_BRANCH_LOCAL; + if (!strcasecmp(var+ofs, "current")) + return COLOR_BRANCH_CURRENT; + die("bad config variable '%s'", var); +} + +int git_branch_config(const char *var, const char *value) +{ + if (!strcmp(var, "color.branch")) { + branch_use_color = git_config_colorbool(var, value); + return 0; + } + if (!strncmp(var, "color.branch.", 13)) { + int slot = parse_branch_color_slot(var, 13); + color_parse(value, var, branch_colors[slot]); + return 0; + } + return git_default_config(var, value); +} + +const char *branch_get_color(enum color_branch ix) +{ + if (branch_use_color) + return branch_colors[ix]; + return ""; +} + static int in_merge_bases(const unsigned char *sha1, struct commit *rev1, struct commit *rev2) @@ -38,12 +91,16 @@ static int in_merge_bases(const unsigned char *sha1, static void delete_branches(int argc, const char **argv, int force) { - struct commit *rev, *head_rev; + struct commit *rev, *head_rev = head_rev; unsigned char sha1[20]; char *name; int i; - head_rev = lookup_commit_reference(head_sha1); + if (!force) { + head_rev = lookup_commit_reference(head_sha1); + if (!head_rev) + die("Couldn't look up commit object for HEAD"); + } for (i = 0; i < argc; i++) { if (!strcmp(head, argv[i])) die("Cannot delete the branch you are currently on."); @@ -53,8 +110,8 @@ static void delete_branches(int argc, const char **argv, int force) die("Branch '%s' not found.", argv[i]); rev = lookup_commit_reference(sha1); - if (!rev || !head_rev) - die("Couldn't look up commit objects."); + if (!rev) + die("Couldn't look up commit object for '%s'", name); /* This checks whether the merge bases of branch and * HEAD contains branch -- which means that the HEAD @@ -87,10 +144,11 @@ static void delete_branches(int argc, const char **argv, int force) struct ref_item { char *name; unsigned int kind; + unsigned char sha1[20]; }; struct ref_list { - int index, alloc; + int index, alloc, maxwidth; struct ref_item *list; int kinds; }; @@ -100,6 +158,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, struct ref_list *ref_list = (struct ref_list*)(cb_data); struct ref_item *newitem; int kind = REF_UNKNOWN_TYPE; + int len; /* Detect kind */ if (!strncmp(refname, "refs/heads/", 11)) { @@ -128,6 +187,10 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, newitem = &(ref_list->list[ref_list->index++]); newitem->name = xstrdup(refname); newitem->kind = kind; + hashcpy(newitem->sha1, sha1); + len = strlen(newitem->name); + if (len > ref_list->maxwidth) + ref_list->maxwidth = len; return 0; } @@ -151,11 +214,29 @@ static int ref_cmp(const void *r1, const void *r2) return strcmp(c1->name, c2->name); } -static void print_ref_list(int kinds) +static void print_ref_info(const unsigned char *sha1, int abbrev) +{ + struct commit *commit; + char subject[256]; + + + commit = lookup_commit(sha1); + if (commit && !parse_commit(commit)) + pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, + subject, sizeof(subject), 0, + NULL, NULL, 0); + else + strcpy(subject, " **** invalid ref ****"); + + printf(" %s %s\n", find_unique_abbrev(sha1, abbrev), subject); +} + +static void print_ref_list(int kinds, int verbose, int abbrev) { int i; char c; struct ref_list ref_list; + int color; memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; @@ -164,12 +245,38 @@ static void print_ref_list(int kinds) qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); for (i = 0; i < ref_list.index; i++) { + switch( ref_list.list[i].kind ) { + case REF_LOCAL_BRANCH: + color = COLOR_BRANCH_LOCAL; + break; + case REF_REMOTE_BRANCH: + color = COLOR_BRANCH_REMOTE; + break; + default: + color = COLOR_BRANCH_PLAIN; + break; + } + c = ' '; if (ref_list.list[i].kind == REF_LOCAL_BRANCH && - !strcmp(ref_list.list[i].name, head)) + !strcmp(ref_list.list[i].name, head)) { c = '*'; + color = COLOR_BRANCH_CURRENT; + } - printf("%c %s\n", c, ref_list.list[i].name); + if (verbose) { + printf("%c %s%-*s%s", c, + branch_get_color(color), + ref_list.maxwidth, + ref_list.list[i].name, + branch_get_color(COLOR_BRANCH_RESET)); + print_ref_info(ref_list.list[i].sha1, abbrev); + } + else + printf("%c %s%s%s\n", c, + branch_get_color(color), + ref_list.list[i].name, + branch_get_color(COLOR_BRANCH_RESET)); } free_ref_list(&ref_list); @@ -212,14 +319,47 @@ static void create_branch(const char *name, const char *start, die("Failed to write ref: %s.", strerror(errno)); } +static void rename_branch(const char *oldname, const char *newname, int force) +{ + char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100]; + unsigned char sha1[20]; + + if (snprintf(oldref, sizeof(oldref), "refs/heads/%s", oldname) > sizeof(oldref)) + die("Old branchname too long"); + + if (check_ref_format(oldref)) + die("Invalid branch name: %s", oldref); + + if (snprintf(newref, sizeof(newref), "refs/heads/%s", newname) > sizeof(newref)) + die("New branchname too long"); + + if (check_ref_format(newref)) + die("Invalid branch name: %s", newref); + + if (resolve_ref(newref, sha1, 1, NULL) && !force) + die("A branch named '%s' already exists.", newname); + + snprintf(logmsg, sizeof(logmsg), "Branch: renamed %s to %s", + oldref, newref); + + if (rename_ref(oldref, newref, logmsg)) + die("Branch rename failed"); + + if (!strcmp(oldname, head) && create_symref("HEAD", newref)) + die("Branch renamed to %s, but HEAD is not updated!", newname); +} + int cmd_branch(int argc, const char **argv, const char *prefix) { int delete = 0, force_delete = 0, force_create = 0; + int rename = 0, force_rename = 0; + int verbose = 0, abbrev = DEFAULT_ABBREV; int reflog = 0; int kinds = REF_LOCAL_BRANCH; int i; - git_config(git_default_config); + setup_ident(); + git_config(git_branch_config); for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -243,6 +383,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix) force_create = 1; continue; } + if (!strcmp(arg, "-m")) { + rename = 1; + continue; + } + if (!strcmp(arg, "-M")) { + rename = 1; + force_rename = 1; + continue; + } if (!strcmp(arg, "-r")) { kinds = REF_REMOTE_BRANCH; continue; @@ -255,9 +404,29 @@ int cmd_branch(int argc, const char **argv, const char *prefix) reflog = 1; continue; } + if (!strncmp(arg, "--abbrev=", 9)) { + abbrev = atoi(arg+9); + continue; + } + if (!strcmp(arg, "-v")) { + verbose = 1; + continue; + } + if (!strcmp(arg, "--color")) { + branch_use_color = 1; + continue; + } + if (!strcmp(arg, "--no-color")) { + branch_use_color = 0; + continue; + } usage(builtin_branch_usage); } + if ((delete && rename) || (delete && force_create) || + (rename && force_create)) + usage(builtin_branch_usage); + head = xstrdup(resolve_ref("HEAD", head_sha1, 0, NULL)); if (!head) die("Failed to resolve HEAD as a valid ref."); @@ -268,7 +437,11 @@ 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(kinds); + print_ref_list(kinds, verbose, abbrev); + else if (rename && (i == argc - 1)) + rename_branch(head, argv[i], force_rename); + else if (rename && (i == argc - 2)) + rename_branch(argv[i], argv[i + 1], force_rename); else if (i == argc - 1) create_branch(argv[i], head, force_create, reflog); else if (i == argc - 2)