X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=builtin-branch.c;h=5f5c1823cb27cf1173c87f43bd0d2de95a06bf46;hb=b67a43bb8f4a8ffb64f26b7351c3b0b90239696a;hp=8956d0f84213afbd0e53e39bc863c05960f524f0;hpb=078f8380f65acfdffee077a642e982453277873a;p=git.git diff --git a/builtin-branch.c b/builtin-branch.c index 8956d0f84..5f5c1823c 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -1,7 +1,7 @@ /* * Builtin "git branch" * - * Copyright (c) 2006 Kristian Høgsberg + * Copyright (c) 2006 Kristian Høgsberg * Based on git-branch.sh by Junio C Hamano. */ @@ -10,6 +10,7 @@ #include "refs.h" #include "commit.h" #include "builtin.h" +#include "remote.h" static const char builtin_branch_usage[] = "git-branch [-r] (-d | -D) | [--track | --no-track] [-l] [-f] [] | (-m | -M) [] | [--color | --no-color] [-r | -a] [-v [--abbrev= | --no-abbrev]]"; @@ -22,7 +23,7 @@ static const char builtin_branch_usage[] = static const char *head; static unsigned char head_sha1[20]; -static int branch_track_remotes; +static int branch_track = 1; static int branch_use_color; static char branch_colors[][COLOR_MAXLEN] = { @@ -55,7 +56,7 @@ static int parse_branch_color_slot(const char *var, int ofs) die("bad config variable '%s'", var); } -int git_branch_config(const char *var, const char *value) +static int git_branch_config(const char *var, const char *value) { if (!strcmp(var, "color.branch")) { branch_use_color = git_config_colorbool(var, value); @@ -67,12 +68,12 @@ int git_branch_config(const char *var, const char *value) return 0; } if (!strcmp(var, "branch.autosetupmerge")) - branch_track_remotes = git_config_bool(var, value); + branch_track = git_config_bool(var, value); return git_default_config(var, value); } -const char *branch_get_color(enum color_branch ix) +static const char *branch_get_color(enum color_branch ix) { if (branch_use_color) return branch_colors[ix]; @@ -85,6 +86,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds) unsigned char sha1[20]; char *name = NULL; const char *fmt, *remote; + char section[PATH_MAX]; int i; int ret = 0; @@ -152,9 +154,13 @@ static int delete_branches(int argc, const char **argv, int force, int kinds) error("Error deleting %sbranch '%s'", remote, argv[i]); ret = 1; - } else + } else { printf("Deleted %sbranch %s.\n", remote, argv[i]); - + snprintf(section, sizeof(section), "branch.%s", + argv[i]); + if (git_config_rename_section(section, NULL) < 0) + warning("Update of config-file failed"); + } } if (name) @@ -242,7 +248,6 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, char c; int color; struct commit *commit; - char subject[256]; switch (item->kind) { case REF_LOCAL_BRANCH: @@ -263,17 +268,23 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, } if (verbose) { + char *subject = NULL; + unsigned long subject_len = 0; + const char *sub = " **** invalid ref ****"; + commit = lookup_commit(item->sha1); - if (commit && !parse_commit(commit)) + if (commit && !parse_commit(commit)) { pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, - subject, sizeof(subject), 0, + &subject, &subject_len, 0, NULL, NULL, 0); - else - strcpy(subject, " **** invalid ref ****"); + sub = subject; + } printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color), maxwidth, item->name, branch_get_color(COLOR_BRANCH_RESET), - find_unique_abbrev(item->sha1, abbrev), subject); + find_unique_abbrev(item->sha1, abbrev), sub); + if (subject) + free(subject); } else { printf("%c %s%s%s\n", c, branch_get_color(color), item->name, branch_get_color(COLOR_BRANCH_RESET)); @@ -314,110 +325,70 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev) free_ref_list(&ref_list); } -static char *config_repo; -static char *config_remote; -static const char *start_ref; -static int start_len; -static int base_len; +struct tracking { + struct refspec spec; + char *src; + const char *remote; + int matches; +}; -static int get_remote_branch_name(const char *value) +static int find_tracked_branch(struct remote *remote, void *priv) { - const char *colon; - const char *end; - - if (*value == '+') - value++; - - colon = strchr(value, ':'); - if (!colon) - return 0; - - end = value + strlen(value); - - /* Try an exact match first. */ - if (!strcmp(colon + 1, start_ref)) { - /* Truncate the value before the colon. */ - nfasprintf(&config_repo, "%.*s", colon - value, value); - return 1; - } - - /* Try with a wildcard match now. */ - if (end - value > 2 && end[-2] == '/' && end[-1] == '*' && - colon - value > 2 && colon[-2] == '/' && colon[-1] == '*' && - (end - 2) - (colon + 1) == base_len && - !strncmp(colon + 1, start_ref, base_len)) { - /* Replace the star with the remote branch name. */ - nfasprintf(&config_repo, "%.*s%s", - (colon - 2) - value, value, - start_ref + base_len); - return 1; + struct tracking *tracking = priv; + + if (!remote_find_tracking(remote, &tracking->spec)) { + if (++tracking->matches == 1) { + tracking->src = tracking->spec.src; + tracking->remote = remote->name; + } else { + free(tracking->spec.src); + if (tracking->src) { + free(tracking->src); + tracking->src = NULL; + } + } + tracking->spec.src = NULL; } return 0; } -static int get_remote_config(const char *key, const char *value) -{ - const char *var; - if (prefixcmp(key, "remote.")) - return 0; - - var = strrchr(key, '.'); - if (var == key + 6) - return 0; - - if (!strcmp(var, ".fetch") && get_remote_branch_name(value)) - nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7); - return 0; -} - -static void set_branch_merge(const char *name, const char *config_remote, - const char *config_repo) +/* + * This is called when new_ref is branched off of orig_ref, and tries + * to infer the settings for branch..{remote,merge} from the + * config. + */ +static int setup_tracking(const char *new_ref, const char *orig_ref) { char key[1024]; - if (sizeof(key) <= - snprintf(key, sizeof(key), "branch.%s.remote", name)) - die("what a long branch name you have!"); - git_config_set(key, config_remote); - - /* - * We do not have to check if we have enough space for - * the 'merge' key, since it's shorter than the - * previous 'remote' key, which we already checked. - */ - snprintf(key, sizeof(key), "branch.%s.merge", name); - git_config_set(key, config_repo); -} + struct tracking tracking; -static void set_branch_defaults(const char *name, const char *real_ref) -{ - const char *slash = strrchr(real_ref, '/'); - - if (!slash) - return; - - start_ref = real_ref; - start_len = strlen(real_ref); - base_len = slash - real_ref; - git_config(get_remote_config); - if (!config_repo && !config_remote && - !prefixcmp(real_ref, "refs/heads/")) { - set_branch_merge(name, ".", real_ref); - printf("Branch %s set up to track local branch %s.\n", - name, real_ref); - } + if (strlen(new_ref) > 1024 - 7 - 7 - 1) + return error("Tracking not set up: name too long: %s", + new_ref); - if (config_repo && config_remote) { - set_branch_merge(name, config_remote, config_repo); + memset(&tracking, 0, sizeof(tracking)); + tracking.spec.dst = (char *)orig_ref; + if (for_each_remote(find_tracked_branch, &tracking) || + !tracking.matches) + return 1; + + if (tracking.matches > 1) + return error("Not tracking: ambiguous information for ref %s", + orig_ref); + + if (tracking.matches == 1) { + sprintf(key, "branch.%s.remote", new_ref); + git_config_set(key, tracking.remote ? tracking.remote : "."); + sprintf(key, "branch.%s.merge", new_ref); + git_config_set(key, tracking.src); + free(tracking.src); printf("Branch %s set up to track remote branch %s.\n", - name, real_ref); + new_ref, orig_ref); } - if (config_repo) - free(config_repo); - if (config_remote) - free(config_remote); + return 0; } static void create_branch(const char *name, const char *start_name, @@ -462,7 +433,7 @@ static void create_branch(const char *name, const char *start_name, die("Not a valid branch point: '%s'.", start_name); hashcpy(sha1, commit->object.sha1); - lock = lock_any_ref_for_update(ref, NULL); + lock = lock_any_ref_for_update(ref, NULL, 0); if (!lock) die("Failed to lock ref for update: %s.", strerror(errno)); @@ -480,7 +451,7 @@ static void create_branch(const char *name, const char *start_name, automatically merges from there. So far, this is only done for remotes registered via .git/config. */ if (real_ref && track) - set_branch_defaults(name, real_ref); + setup_tracking(name, real_ref); if (write_ref_sha1(lock, sha1, msg) < 0) die("Failed to write ref: %s.", strerror(errno)); @@ -539,7 +510,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) int i; git_config(git_branch_config); - track = branch_track_remotes; + track = branch_track; for (i = 1; i < argc; i++) { const char *arg = argv[i];