diff options
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 573 |
1 files changed, 356 insertions, 217 deletions
@@ -8,6 +8,7 @@ #include "tag.h" #include "string-list.h" #include "mergesort.h" +#include "argv-array.h" enum map_direction { FROM_SRC, FROM_DST }; @@ -42,23 +43,18 @@ struct rewrites { static struct remote **remotes; static int remotes_alloc; static int remotes_nr; +static struct hashmap remotes_hash; static struct branch **branches; static int branches_alloc; static int branches_nr; static struct branch *current_branch; -static const char *default_remote_name; -static const char *branch_pushremote_name; static const char *pushremote_name; -static int explicit_default_remote_name; static struct rewrites rewrites; static struct rewrites rewrites_push; -#define BUF_SIZE (2048) -static char buffer[BUF_SIZE]; - static int valid_remote(const struct remote *remote) { return (!!remote->url) || (!!remote->foreign_vcs); @@ -67,7 +63,6 @@ static int valid_remote(const struct remote *remote) static const char *alias_url(const char *url, struct rewrites *r) { int i, j; - char *ret; struct counted_string *longest; int longest_i; @@ -88,11 +83,7 @@ static const char *alias_url(const char *url, struct rewrites *r) if (!longest) return url; - ret = xmalloc(r->rewrite[longest_i]->baselen + - (strlen(url) - longest->len) + 1); - strcpy(ret, r->rewrite[longest_i]->base); - strcpy(ret + r->rewrite[longest_i]->baselen, url + longest->len); - return ret; + return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len); } static void add_push_refspec(struct remote *remote, const char *ref) @@ -136,26 +127,51 @@ static void add_url_alias(struct remote *remote, const char *url) add_pushurl_alias(remote, url); } +struct remotes_hash_key { + const char *str; + int len; +}; + +static int remotes_hash_cmp(const struct remote *a, const struct remote *b, const struct remotes_hash_key *key) +{ + if (key) + return strncmp(a->name, key->str, key->len) || a->name[key->len]; + else + return strcmp(a->name, b->name); +} + +static inline void init_remotes_hash(void) +{ + if (!remotes_hash.cmpfn) + hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, 0); +} + static struct remote *make_remote(const char *name, int len) { - struct remote *ret; - int i; + struct remote *ret, *replaced; + struct remotes_hash_key lookup; + struct hashmap_entry lookup_entry; - for (i = 0; i < remotes_nr; i++) { - if (len ? (!strncmp(name, remotes[i]->name, len) && - !remotes[i]->name[len]) : - !strcmp(name, remotes[i]->name)) - return remotes[i]; - } + if (!len) + len = strlen(name); + + init_remotes_hash(); + lookup.str = name; + lookup.len = len; + hashmap_entry_init(&lookup_entry, memhash(name, len)); + + if ((ret = hashmap_get(&remotes_hash, &lookup_entry, &lookup)) != NULL) + return ret; ret = xcalloc(1, sizeof(struct remote)); ret->prune = -1; /* unspecified */ ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc); remotes[remotes_nr++] = ret; - if (len) - ret->name = xstrndup(name, len); - else - ret->name = xstrdup(name); + ret->name = xstrndup(name, len); + + hashmap_entry_init(ret, lookup_entry.hash); + replaced = hashmap_put(&remotes_hash, ret); + assert(replaced == NULL); /* no previous entry overwritten */ return ret; } @@ -170,7 +186,6 @@ static struct branch *make_branch(const char *name, int len) { struct branch *ret; int i; - char *refname; for (i = 0; i < branches_nr; i++) { if (len ? (!strncmp(name, branches[i]->name, len) && @@ -186,10 +201,7 @@ static struct branch *make_branch(const char *name, int len) ret->name = xstrndup(name, len); else ret->name = xstrdup(name); - refname = xmalloc(strlen(name) + strlen("refs/heads/") + 1); - strcpy(refname, "refs/heads/"); - strcpy(refname + strlen("refs/heads/"), ret->name); - ret->refname = refname; + ret->refname = xstrfmt("refs/heads/%s", ret->name); return ret; } @@ -229,106 +241,77 @@ static void add_instead_of(struct rewrite *rewrite, const char *instead_of) rewrite->instead_of_nr++; } +static const char *skip_spaces(const char *s) +{ + while (isspace(*s)) + s++; + return s; +} + static void read_remotes_file(struct remote *remote) { + struct strbuf buf = STRBUF_INIT; FILE *f = fopen(git_path("remotes/%s", remote->name), "r"); if (!f) return; remote->origin = REMOTE_REMOTES; - while (fgets(buffer, BUF_SIZE, f)) { - int value_list; - char *s, *p; - - if (starts_with(buffer, "URL:")) { - value_list = 0; - s = buffer + 4; - } else if (starts_with(buffer, "Push:")) { - value_list = 1; - s = buffer + 5; - } else if (starts_with(buffer, "Pull:")) { - value_list = 2; - s = buffer + 5; - } else - continue; - - while (isspace(*s)) - s++; - if (!*s) - continue; + while (strbuf_getline(&buf, f, '\n') != EOF) { + const char *v; - p = s + strlen(s); - while (isspace(p[-1])) - *--p = 0; + strbuf_rtrim(&buf); - switch (value_list) { - case 0: - add_url_alias(remote, xstrdup(s)); - break; - case 1: - add_push_refspec(remote, xstrdup(s)); - break; - case 2: - add_fetch_refspec(remote, xstrdup(s)); - break; - } + if (skip_prefix(buf.buf, "URL:", &v)) + add_url_alias(remote, xstrdup(skip_spaces(v))); + else if (skip_prefix(buf.buf, "Push:", &v)) + add_push_refspec(remote, xstrdup(skip_spaces(v))); + else if (skip_prefix(buf.buf, "Pull:", &v)) + add_fetch_refspec(remote, xstrdup(skip_spaces(v))); } + strbuf_release(&buf); fclose(f); } static void read_branches_file(struct remote *remote) { char *frag; - struct strbuf branch = STRBUF_INIT; - int n = 1000; - FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r"); - char *s, *p; - int len; + struct strbuf buf = STRBUF_INIT; + FILE *f = fopen(git_path("branches/%s", remote->name), "r"); if (!f) return; - s = fgets(buffer, BUF_SIZE, f); + + strbuf_getline(&buf, f, '\n'); fclose(f); - if (!s) - return; - while (isspace(*s)) - s++; - if (!*s) + strbuf_trim(&buf); + if (!buf.len) { + strbuf_release(&buf); return; + } + remote->origin = REMOTE_BRANCHES; - p = s + strlen(s); - while (isspace(p[-1])) - *--p = 0; - len = p - s; - p = xmalloc(len + 1); - strcpy(p, s); /* * The branches file would have URL and optionally * #branch specified. The "master" (or specified) branch is - * fetched and stored in the local branch of the same name. + * fetched and stored in the local branch matching the + * remote name. */ - frag = strchr(p, '#'); - if (frag) { + frag = strchr(buf.buf, '#'); + if (frag) *(frag++) = '\0'; - strbuf_addf(&branch, "refs/heads/%s", frag); - } else - strbuf_addstr(&branch, "refs/heads/master"); + else + frag = "master"; + + add_url_alias(remote, strbuf_detach(&buf, NULL)); + add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s", + frag, remote->name)); - strbuf_addf(&branch, ":refs/heads/%s", remote->name); - add_url_alias(remote, p); - add_fetch_refspec(remote, strbuf_detach(&branch, NULL)); /* * Cogito compatible push: push current HEAD to remote #branch * (master if missing) */ - strbuf_init(&branch, 0); - strbuf_addstr(&branch, "HEAD"); - if (frag) - strbuf_addf(&branch, ":refs/heads/%s", frag); - else - strbuf_addstr(&branch, ":refs/heads/master"); - add_push_refspec(remote, strbuf_detach(&branch, NULL)); + add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag)); remote->fetch_tags = 1; /* always auto-follow */ } @@ -345,16 +328,9 @@ static int handle_config(const char *key, const char *value, void *cb) return 0; branch = make_branch(name, subkey - name); if (!strcmp(subkey, ".remote")) { - if (git_config_string(&branch->remote_name, key, value)) - return -1; - if (branch == current_branch) { - default_remote_name = branch->remote_name; - explicit_default_remote_name = 1; - } + return git_config_string(&branch->remote_name, key, value); } else if (!strcmp(subkey, ".pushremote")) { - if (branch == current_branch) - if (git_config_string(&branch_pushremote_name, key, value)) - return -1; + return git_config_string(&branch->pushremote_name, key, value); } else if (!strcmp(subkey, ".merge")) { if (!value) return config_error_nonbool(key); @@ -479,24 +455,22 @@ static void alias_all_urls(void) static void read_config(void) { + static int loaded; unsigned char sha1[20]; const char *head_ref; int flag; - if (default_remote_name) /* did this already */ + + if (loaded) return; - default_remote_name = "origin"; + loaded = 1; + current_branch = NULL; - head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag); + head_ref = resolve_ref_unsafe("HEAD", 0, sha1, &flag); if (head_ref && (flag & REF_ISSYMREF) && - starts_with(head_ref, "refs/heads/")) { - current_branch = - make_branch(head_ref + strlen("refs/heads/"), 0); + skip_prefix(head_ref, "refs/heads/", &head_ref)) { + current_branch = make_branch(head_ref, 0); } git_config(handle_config, NULL); - if (branch_pushremote_name) { - free((char *)pushremote_name); - pushremote_name = branch_pushremote_name; - } alias_all_urls(); } @@ -675,22 +649,45 @@ static int valid_remote_nick(const char *name) return !strchr(name, '/'); /* no slash */ } -static struct remote *remote_get_1(const char *name, const char *pushremote_name) +const char *remote_for_branch(struct branch *branch, int *explicit) +{ + if (branch && branch->remote_name) { + if (explicit) + *explicit = 1; + return branch->remote_name; + } + if (explicit) + *explicit = 0; + return "origin"; +} + +const char *pushremote_for_branch(struct branch *branch, int *explicit) +{ + if (branch && branch->pushremote_name) { + if (explicit) + *explicit = 1; + return branch->pushremote_name; + } + if (pushremote_name) { + if (explicit) + *explicit = 1; + return pushremote_name; + } + return remote_for_branch(branch, explicit); +} + +static struct remote *remote_get_1(const char *name, + const char *(*get_default)(struct branch *, int *)) { struct remote *ret; int name_given = 0; + read_config(); + if (name) name_given = 1; - else { - if (pushremote_name) { - name = pushremote_name; - name_given = 1; - } else { - name = default_remote_name; - name_given = explicit_default_remote_name; - } - } + else + name = get_default(current_branch, &name_given); ret = make_remote(name, 0); if (valid_remote_nick(name)) { @@ -710,25 +707,26 @@ static struct remote *remote_get_1(const char *name, const char *pushremote_name struct remote *remote_get(const char *name) { - read_config(); - return remote_get_1(name, NULL); + return remote_get_1(name, remote_for_branch); } struct remote *pushremote_get(const char *name) { - read_config(); - return remote_get_1(name, pushremote_name); + return remote_get_1(name, pushremote_for_branch); } int remote_is_configured(const char *name) { - int i; + struct remotes_hash_key lookup; + struct hashmap_entry lookup_entry; read_config(); - for (i = 0; i < remotes_nr; i++) - if (!strcmp(name, remotes[i]->name)) - return 1; - return 0; + init_remotes_hash(); + lookup.str = name; + lookup.len = strlen(name); + hashmap_entry_init(&lookup_entry, memhash(name, lookup.len)); + + return hashmap_get(&remotes_hash, &lookup_entry, &lookup) != NULL; } int for_each_remote(each_remote_fn fn, void *priv) @@ -838,21 +836,14 @@ static int match_name_with_pattern(const char *key, const char *name, ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen && !memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen); if (ret && value) { + struct strbuf sb = STRBUF_INIT; const char *vstar = strchr(value, '*'); - size_t vlen; - size_t vsuffixlen; if (!vstar) die("Value '%s' of pattern has no '*'", value); - vlen = vstar - value; - vsuffixlen = strlen(vstar + 1); - *result = xmalloc(vlen + vsuffixlen + - strlen(name) - - klen - ksuffixlen + 1); - strncpy(*result, value, vlen); - strncpy(*result + vlen, - name + klen, namelen - klen - ksuffixlen); - strcpy(*result + vlen + namelen - klen - ksuffixlen, - vstar + 1); + strbuf_add(&sb, value, vstar - value); + strbuf_add(&sb, name + klen, namelen - klen - ksuffixlen); + strbuf_addstr(&sb, vstar + 1); + *result = strbuf_detach(&sb, NULL); } return ret; } @@ -958,8 +949,8 @@ struct ref *copy_ref(const struct ref *ref) cpy = xmalloc(sizeof(struct ref) + len + 1); memcpy(cpy, ref, sizeof(struct ref) + len + 1); cpy->next = NULL; - cpy->symref = ref->symref ? xstrdup(ref->symref) : NULL; - cpy->remote_status = ref->remote_status ? xstrdup(ref->remote_status) : NULL; + cpy->symref = xstrdup_or_null(ref->symref); + cpy->remote_status = xstrdup_or_null(ref->remote_status); cpy->peer_ref = copy_ref(ref->peer_ref); return cpy; } @@ -1121,7 +1112,8 @@ static char *guess_ref(const char *name, struct ref *peer) struct strbuf buf = STRBUF_INIT; unsigned char sha1[20]; - const char *r = resolve_ref_unsafe(peer->name, sha1, 1, NULL); + const char *r = resolve_ref_unsafe(peer->name, RESOLVE_REF_READING, + sha1, NULL); if (!r) return NULL; @@ -1182,7 +1174,9 @@ static int match_explicit(struct ref *src, struct ref *dst, unsigned char sha1[20]; int flag; - dst_value = resolve_ref_unsafe(matched_src->name, sha1, 1, &flag); + dst_value = resolve_ref_unsafe(matched_src->name, + RESOLVE_REF_READING, + sha1, &flag); if (!dst_value || ((flag & REF_ISSYMREF) && !starts_with(dst_value, "refs/heads/"))) @@ -1194,7 +1188,7 @@ static int match_explicit(struct ref *src, struct ref *dst, case 1: break; case 0: - if (!memcmp(dst_value, "refs/", 5)) + if (starts_with(dst_value, "refs/")) matched_dst = make_linked_ref(dst_value, dst_tail); else if (is_null_sha1(matched_src->new_sha1)) error("unable to delete '%s': remote ref does not exist", @@ -1336,7 +1330,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds } clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK); - sort_string_list(&dst_tag); + string_list_sort(&dst_tag); /* Collect tags they do not have. */ for (ref = src; ref; ref = ref->next) { @@ -1401,7 +1395,7 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref) for ( ; ref; ref = ref->next) string_list_append_nodup(ref_index, ref->name)->util = ref; - sort_string_list(ref_index); + string_list_sort(ref_index); } /* @@ -1611,6 +1605,43 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, } } +static void set_merge(struct branch *ret) +{ + struct remote *remote; + char *ref; + unsigned char sha1[20]; + int i; + + if (!ret) + return; /* no branch */ + if (ret->merge) + return; /* already run */ + if (!ret->remote_name || !ret->merge_nr) { + /* + * no merge config; let's make sure we don't confuse callers + * with a non-zero merge_nr but a NULL merge + */ + ret->merge_nr = 0; + return; + } + + remote = remote_get(ret->remote_name); + + ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge)); + for (i = 0; i < ret->merge_nr; i++) { + ret->merge[i] = xcalloc(1, sizeof(**ret->merge)); + ret->merge[i]->src = xstrdup(ret->merge_name[i]); + if (!remote_find_tracking(remote, ret->merge[i]) || + strcmp(ret->remote_name, ".")) + continue; + if (dwim_ref(ret->merge_name[i], strlen(ret->merge_name[i]), + sha1, &ref) == 1) + ret->merge[i]->dst = ref; + else + ret->merge[i]->dst = xstrdup(ret->merge_name[i]); + } +} + struct branch *branch_get(const char *name) { struct branch *ret; @@ -1620,20 +1651,7 @@ struct branch *branch_get(const char *name) ret = current_branch; else ret = make_branch(name, 0); - if (ret && ret->remote_name) { - ret->remote = remote_get(ret->remote_name); - if (ret->merge_nr) { - int i; - ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge)); - for (i = 0; i < ret->merge_nr; i++) { - ret->merge[i] = xcalloc(1, sizeof(**ret->merge)); - ret->merge[i]->src = xstrdup(ret->merge_name[i]); - if (remote_find_tracking(ret->remote, ret->merge[i]) - && !strcmp(ret->remote_name, ".")) - ret->merge[i]->dst = xstrdup(ret->merge_name[i]); - } - } - } + set_merge(ret); return ret; } @@ -1651,12 +1669,136 @@ int branch_merge_matches(struct branch *branch, return refname_match(branch->merge[i]->src, refname); } +__attribute((format (printf,2,3))) +static const char *error_buf(struct strbuf *err, const char *fmt, ...) +{ + if (err) { + va_list ap; + va_start(ap, fmt); + strbuf_vaddf(err, fmt, ap); + va_end(ap); + } + return NULL; +} + +const char *branch_get_upstream(struct branch *branch, struct strbuf *err) +{ + if (!branch) + return error_buf(err, _("HEAD does not point to a branch")); + + if (!branch->merge || !branch->merge[0]) { + /* + * no merge config; is it because the user didn't define any, + * or because it is not a real branch, and get_branch + * auto-vivified it? + */ + if (!ref_exists(branch->refname)) + return error_buf(err, _("no such branch: '%s'"), + branch->name); + return error_buf(err, + _("no upstream configured for branch '%s'"), + branch->name); + } + + if (!branch->merge[0]->dst) + return error_buf(err, + _("upstream branch '%s' not stored as a remote-tracking branch"), + branch->merge[0]->src); + + return branch->merge[0]->dst; +} + +static const char *tracking_for_push_dest(struct remote *remote, + const char *refname, + struct strbuf *err) +{ + char *ret; + + ret = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); + if (!ret) + return error_buf(err, + _("push destination '%s' on remote '%s' has no local tracking branch"), + refname, remote->name); + return ret; +} + +static const char *branch_get_push_1(struct branch *branch, struct strbuf *err) +{ + struct remote *remote; + + if (!branch) + return error_buf(err, _("HEAD does not point to a branch")); + + remote = remote_get(pushremote_for_branch(branch, NULL)); + if (!remote) + return error_buf(err, + _("branch '%s' has no remote for pushing"), + branch->name); + + if (remote->push_refspec_nr) { + char *dst; + const char *ret; + + dst = apply_refspecs(remote->push, remote->push_refspec_nr, + branch->refname); + if (!dst) + return error_buf(err, + _("push refspecs for '%s' do not include '%s'"), + remote->name, branch->name); + + ret = tracking_for_push_dest(remote, dst, err); + free(dst); + return ret; + } + + if (remote->mirror) + return tracking_for_push_dest(remote, branch->refname, err); + + switch (push_default) { + case PUSH_DEFAULT_NOTHING: + return error_buf(err, _("push has no destination (push.default is 'nothing')")); + + case PUSH_DEFAULT_MATCHING: + case PUSH_DEFAULT_CURRENT: + return tracking_for_push_dest(remote, branch->refname, err); + + case PUSH_DEFAULT_UPSTREAM: + return branch_get_upstream(branch, err); + + case PUSH_DEFAULT_UNSPECIFIED: + case PUSH_DEFAULT_SIMPLE: + { + const char *up, *cur; + + up = branch_get_upstream(branch, err); + if (!up) + return NULL; + cur = tracking_for_push_dest(remote, branch->refname, err); + if (!cur) + return NULL; + if (strcmp(cur, up)) + return error_buf(err, + _("cannot resolve 'simple' push to a single destination")); + return cur; + } + } + + die("BUG: unhandled push situation"); +} + +const char *branch_get_push(struct branch *branch, struct strbuf *err) +{ + if (!branch->push_tracking_ref) + branch->push_tracking_ref = branch_get_push_1(branch, err); + return branch->push_tracking_ref; +} + static int ignore_symref_update(const char *refname) { unsigned char sha1[20]; int flag; - if (!resolve_ref_unsafe(refname, sha1, 0, &flag)) + if (!resolve_ref_unsafe(refname, 0, sha1, &flag)) return 0; /* non-existing refs are OK */ return (flag & REF_ISSYMREF); } @@ -1797,10 +1939,8 @@ int resolve_remote_symref(struct ref *ref, struct ref *list) static void unmark_and_free(struct commit_list *list, unsigned int mark) { while (list) { - struct commit_list *temp = list; - temp->item->object.flags &= ~mark; - list = temp->next; - free(temp); + struct commit *commit = pop_commit(&list); + commit->object.flags &= ~mark; } } @@ -1845,27 +1985,30 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1) /* * Compare a branch with its upstream, and save their differences (number - * of commits) in *num_ours and *num_theirs. + * of commits) in *num_ours and *num_theirs. The name of the upstream branch + * (or NULL if no upstream is defined) is returned via *upstream_name, if it + * is not itself NULL. * - * Return 0 if branch has no upstream (no base), -1 if upstream is missing - * (with "gone" base), otherwise 1 (with base). + * Returns -1 if num_ours and num_theirs could not be filled in (e.g., no + * upstream defined, or ref does not exist), 0 otherwise. */ -int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) +int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, + const char **upstream_name) { unsigned char sha1[20]; struct commit *ours, *theirs; - char symmetric[84]; struct rev_info revs; - const char *rev_argv[10], *base; - int rev_argc; + const char *base; + struct argv_array argv = ARGV_ARRAY_INIT; /* Cannot stat unless we are marked to build on top of somebody else. */ - if (!branch || - !branch->merge || !branch->merge[0] || !branch->merge[0]->dst) - return 0; + base = branch_get_upstream(branch, NULL); + if (upstream_name) + *upstream_name = base; + if (!base) + return -1; /* Cannot stat if what we used to build on no longer exists */ - base = branch->merge[0]->dst; if (read_ref(base, sha1)) return -1; theirs = lookup_commit_reference(sha1); @@ -1881,24 +2024,21 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) /* are we the same? */ if (theirs == ours) { *num_theirs = *num_ours = 0; - return 1; + return 0; } /* Run "rev-list --left-right ours...theirs" internally... */ - rev_argc = 0; - rev_argv[rev_argc++] = NULL; - rev_argv[rev_argc++] = "--left-right"; - rev_argv[rev_argc++] = symmetric; - rev_argv[rev_argc++] = "--"; - rev_argv[rev_argc] = NULL; - - strcpy(symmetric, sha1_to_hex(ours->object.sha1)); - strcpy(symmetric + 40, "..."); - strcpy(symmetric + 43, sha1_to_hex(theirs->object.sha1)); + argv_array_push(&argv, ""); /* ignored */ + argv_array_push(&argv, "--left-right"); + argv_array_pushf(&argv, "%s...%s", + sha1_to_hex(ours->object.sha1), + sha1_to_hex(theirs->object.sha1)); + argv_array_push(&argv, "--"); init_revisions(&revs, NULL); - setup_revisions(rev_argc, rev_argv, &revs, NULL); - prepare_revision_walk(&revs); + setup_revisions(argv.argc, argv.argv, &revs, NULL); + if (prepare_revision_walk(&revs)) + die("revision walk setup failed"); /* ... and count the commits on each side. */ *num_ours = 0; @@ -1916,7 +2056,9 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) /* clear object flags smudged by the above traversal */ clear_commit_marks(ours, ALL_REV_FLAGS); clear_commit_marks(theirs, ALL_REV_FLAGS); - return 1; + + argv_array_clear(&argv); + return 0; } /* @@ -1925,24 +2067,17 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) int format_tracking_info(struct branch *branch, struct strbuf *sb) { int ours, theirs; - const char *base; + const char *full_base; + char *base; int upstream_is_gone = 0; - switch (stat_tracking_info(branch, &ours, &theirs)) { - case 0: - /* no base */ - return 0; - case -1: - /* with "gone" base */ + if (stat_tracking_info(branch, &ours, &theirs, &full_base) < 0) { + if (!full_base) + return 0; upstream_is_gone = 1; - break; - default: - /* with base */ - break; } - base = branch->merge[0]->dst; - base = shorten_unambiguous_ref(base, 0); + base = shorten_unambiguous_ref(full_base, 0); if (upstream_is_gone) { strbuf_addf(sb, _("Your branch is based on '%s', but the upstream is gone.\n"), @@ -1988,10 +2123,12 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) strbuf_addf(sb, _(" (use \"git pull\" to merge the remote branch into yours)\n")); } + free(base); return 1; } -static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +static int one_local_ref(const char *refname, const struct object_id *oid, + int flag, void *cb_data) { struct ref ***local_tail = cb_data; struct ref *ref; @@ -2003,7 +2140,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla len = strlen(refname) + 1; ref = xcalloc(1, sizeof(*ref) + len); - hashcpy(ref->new_sha1, sha1); + hashcpy(ref->new_sha1, oid->hash); memcpy(ref->name, refname, len); **local_tail = ref; *local_tail = &ref->next; @@ -2013,6 +2150,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1, int fla struct ref *get_local_heads(void) { struct ref *local_refs = NULL, **local_tail = &local_refs; + for_each_ref(one_local_ref, &local_tail); return local_refs; } @@ -2065,8 +2203,8 @@ struct stale_heads_info { int ref_count; }; -static int get_stale_heads_cb(const char *refname, - const unsigned char *sha1, int flags, void *cb_data) +static int get_stale_heads_cb(const char *refname, const struct object_id *oid, + int flags, void *cb_data) { struct stale_heads_info *info = cb_data; struct string_list matches = STRING_LIST_INIT_DUP; @@ -2095,7 +2233,7 @@ static int get_stale_heads_cb(const char *refname, if (stale) { struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail); - hashcpy(ref->new_sha1, sha1); + hashcpy(ref->new_sha1, oid->hash); } clean_exit: @@ -2108,13 +2246,14 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet struct ref *ref, *stale_refs = NULL; struct string_list ref_names = STRING_LIST_INIT_NODUP; struct stale_heads_info info; + info.ref_names = &ref_names; info.stale_refs_tail = &stale_refs; info.refs = refs; info.ref_count = ref_count; for (ref = fetch_map; ref; ref = ref->next) string_list_append(&ref_names, ref->name); - sort_string_list(&ref_names); + string_list_sort(&ref_names); for_each_ref(get_stale_heads_cb, &info); string_list_clear(&ref_names, 0); return stale_refs; @@ -2123,7 +2262,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet /* * Compare-and-swap */ -void clear_cas_option(struct push_cas_option *cas) +static void clear_cas_option(struct push_cas_option *cas) { int i; |