diff options
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 419 |
1 files changed, 129 insertions, 290 deletions
@@ -2,6 +2,8 @@ #include "config.h" #include "remote.h" #include "refs.h" +#include "refspec.h" +#include "object-store.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -13,17 +15,6 @@ enum map_direction { FROM_SRC, FROM_DST }; -static struct refspec s_tag_refspec = { - 0, - 1, - 0, - 0, - "refs/tags/*", - "refs/tags/*" -}; - -const struct refspec *tag_refspec = &s_tag_refspec; - struct counted_string { size_t len; const char *s; @@ -87,22 +78,6 @@ static const char *alias_url(const char *url, struct rewrites *r) return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len); } -static void add_push_refspec(struct remote *remote, const char *ref) -{ - ALLOC_GROW(remote->push_refspec, - remote->push_refspec_nr + 1, - remote->push_refspec_alloc); - remote->push_refspec[remote->push_refspec_nr++] = ref; -} - -static void add_fetch_refspec(struct remote *remote, const char *ref) -{ - ALLOC_GROW(remote->fetch_refspec, - remote->fetch_refspec_nr + 1, - remote->fetch_refspec_alloc); - remote->fetch_refspec[remote->fetch_refspec_nr++] = ref; -} - static void add_url(struct remote *remote, const char *url) { ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); @@ -173,9 +148,13 @@ static struct remote *make_remote(const char *name, int len) ret = xcalloc(1, sizeof(struct remote)); ret->prune = -1; /* unspecified */ + ret->prune_tags = -1; /* unspecified */ + ret->name = xstrndup(name, len); + refspec_init(&ret->push, REFSPEC_PUSH); + refspec_init(&ret->fetch, REFSPEC_FETCH); + ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc); remotes[remotes_nr++] = ret; - ret->name = xstrndup(name, len); hashmap_entry_init(ret, lookup_entry.hash); replaced = hashmap_put(&remotes_hash, ret); @@ -273,9 +252,9 @@ static void read_remotes_file(struct remote *remote) 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))); + refspec_append(&remote->push, skip_spaces(v)); else if (skip_prefix(buf.buf, "Pull:", &v)) - add_fetch_refspec(remote, xstrdup(skip_spaces(v))); + refspec_append(&remote->fetch, skip_spaces(v)); } strbuf_release(&buf); fclose(f); @@ -314,15 +293,19 @@ static void read_branches_file(struct remote *remote) 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(&buf, "refs/heads/%s:refs/heads/%s", + frag, remote->name); + refspec_append(&remote->fetch, buf.buf); /* * Cogito compatible push: push current HEAD to remote #branch * (master if missing) */ - add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag)); + strbuf_reset(&buf); + strbuf_addf(&buf, "HEAD:refs/heads/%s", frag); + refspec_append(&remote->push, buf.buf); remote->fetch_tags = 1; /* always auto-follow */ + strbuf_release(&buf); } static int handle_config(const char *key, const char *value, void *cb) @@ -391,6 +374,8 @@ static int handle_config(const char *key, const char *value, void *cb) remote->skip_default_update = git_config_bool(key, value); else if (!strcmp(subkey, "prune")) remote->prune = git_config_bool(key, value); + else if (!strcmp(subkey, "prunetags")) + remote->prune_tags = git_config_bool(key, value); else if (!strcmp(subkey, "url")) { const char *v; if (git_config_string(&v, key, value)) @@ -405,12 +390,14 @@ static int handle_config(const char *key, const char *value, void *cb) const char *v; if (git_config_string(&v, key, value)) return -1; - add_push_refspec(remote, v); + refspec_append(&remote->push, v); + free((char *)v); } else if (!strcmp(subkey, "fetch")) { const char *v; if (git_config_string(&v, key, value)) return -1; - add_fetch_refspec(remote, v); + refspec_append(&remote->fetch, v); + free((char *)v); } else if (!strcmp(subkey, "receivepack")) { const char *v; if (git_config_string(&v, key, value)) @@ -484,158 +471,6 @@ static void read_config(void) alias_all_urls(); } -static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) -{ - int i; - struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs)); - - for (i = 0; i < nr_refspec; i++) { - size_t llen; - int is_glob; - const char *lhs, *rhs; - int flags; - - is_glob = 0; - - lhs = refspec[i]; - if (*lhs == '+') { - rs[i].force = 1; - lhs++; - } - - rhs = strrchr(lhs, ':'); - - /* - * Before going on, special case ":" (or "+:") as a refspec - * for pushing matching refs. - */ - if (!fetch && rhs == lhs && rhs[1] == '\0') { - rs[i].matching = 1; - continue; - } - - if (rhs) { - size_t rlen = strlen(++rhs); - is_glob = (1 <= rlen && strchr(rhs, '*')); - rs[i].dst = xstrndup(rhs, rlen); - } - - llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); - if (1 <= llen && memchr(lhs, '*', llen)) { - if ((rhs && !is_glob) || (!rhs && fetch)) - goto invalid; - is_glob = 1; - } else if (rhs && is_glob) { - goto invalid; - } - - rs[i].pattern = is_glob; - rs[i].src = xstrndup(lhs, llen); - flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); - - if (fetch) { - struct object_id unused; - - /* LHS */ - if (!*rs[i].src) - ; /* empty is ok; it means "HEAD" */ - else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused)) - rs[i].exact_sha1 = 1; /* ok */ - else if (!check_refname_format(rs[i].src, flags)) - ; /* valid looking ref is ok */ - else - goto invalid; - /* RHS */ - if (!rs[i].dst) - ; /* missing is ok; it is the same as empty */ - else if (!*rs[i].dst) - ; /* empty is ok; it means "do not store" */ - else if (!check_refname_format(rs[i].dst, flags)) - ; /* valid looking ref is ok */ - else - goto invalid; - } else { - /* - * LHS - * - empty is allowed; it means delete. - * - when wildcarded, it must be a valid looking ref. - * - otherwise, it must be an extended SHA-1, but - * there is no existing way to validate this. - */ - if (!*rs[i].src) - ; /* empty is ok */ - else if (is_glob) { - if (check_refname_format(rs[i].src, flags)) - goto invalid; - } - else - ; /* anything goes, for now */ - /* - * RHS - * - missing is allowed, but LHS then must be a - * valid looking ref. - * - empty is not allowed. - * - otherwise it must be a valid looking ref. - */ - if (!rs[i].dst) { - if (check_refname_format(rs[i].src, flags)) - goto invalid; - } else if (!*rs[i].dst) { - goto invalid; - } else { - if (check_refname_format(rs[i].dst, flags)) - goto invalid; - } - } - } - return rs; - - invalid: - if (verify) { - /* - * nr_refspec must be greater than zero and i must be valid - * since it is only possible to reach this point from within - * the for loop above. - */ - free_refspec(i+1, rs); - return NULL; - } - die("Invalid refspec '%s'", refspec[i]); -} - -int valid_fetch_refspec(const char *fetch_refspec_str) -{ - struct refspec *refspec; - - refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1); - free_refspec(1, refspec); - return !!refspec; -} - -struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) -{ - return parse_refspec_internal(nr_refspec, refspec, 1, 0); -} - -struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) -{ - return parse_refspec_internal(nr_refspec, refspec, 0, 0); -} - -void free_refspec(int nr_refspec, struct refspec *refspec) -{ - int i; - - if (!refspec) - return; - - for (i = 0; i < nr_refspec; i++) { - free(refspec[i].src); - free(refspec[i].dst); - } - free(refspec); -} - static int valid_remote_nick(const char *name) { if (!name[0] || is_dot_or_dotdot(name)) @@ -690,9 +525,8 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push, pushremote_for_branch(branch, NULL); struct remote *remote = remote_get(remote_name); - if (remote && remote->push_refspec_nr && - (dst = apply_refspecs(remote->push, - remote->push_refspec_nr, + if (remote && remote->push.nr && + (dst = apply_refspecs(&remote->push, branch->refname))) { if (explicit) *explicit = 1; @@ -729,8 +563,6 @@ static struct remote *remote_get_1(const char *name, add_url_alias(ret, name); if (!valid_remote(ret)) return NULL; - ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec); - ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec); return ret; } @@ -761,12 +593,6 @@ int for_each_remote(each_remote_fn fn, void *priv) struct remote *r = remotes[i]; if (!r) continue; - if (!r->fetch) - r->fetch = parse_fetch_refspec(r->fetch_refspec_nr, - r->fetch_refspec); - if (!r->push) - r->push = parse_push_refspec(r->push_refspec_nr, - r->push_refspec); result = fn(r, priv); } return result; @@ -872,7 +698,9 @@ static int match_name_with_pattern(const char *key, const char *name, return ret; } -static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct refspec *query, struct string_list *results) +static void query_refspecs_multiple(struct refspec *rs, + struct refspec_item *query, + struct string_list *results) { int i; int find_src = !query->src; @@ -880,8 +708,8 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct if (find_src && !query->dst) error("query_refspecs_multiple: need either src or dst"); - for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + for (i = 0; i < rs->nr; i++) { + struct refspec_item *refspec = &rs->items[i]; const char *key = find_src ? refspec->dst : refspec->src; const char *value = find_src ? refspec->src : refspec->dst; const char *needle = find_src ? query->dst : query->src; @@ -898,7 +726,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct } } -int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) +int query_refspecs(struct refspec *rs, struct refspec_item *query) { int i; int find_src = !query->src; @@ -908,8 +736,8 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) if (find_src && !query->dst) return error("query_refspecs: need either src or dst"); - for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + for (i = 0; i < rs->nr; i++) { + struct refspec_item *refspec = &rs->items[i]; const char *key = find_src ? refspec->dst : refspec->src; const char *value = find_src ? refspec->src : refspec->dst; @@ -929,23 +757,22 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) return -1; } -char *apply_refspecs(struct refspec *refspecs, int nr_refspec, - const char *name) +char *apply_refspecs(struct refspec *rs, const char *name) { - struct refspec query; + struct refspec_item query; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.src = (char *)name; - if (query_refspecs(refspecs, nr_refspec, &query)) + if (query_refspecs(rs, &query)) return NULL; return query.dst; } -int remote_find_tracking(struct remote *remote, struct refspec *refspec) +int remote_find_tracking(struct remote *remote, struct refspec_item *refspec) { - return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec); + return query_refspecs(&remote->fetch, refspec); } static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen, @@ -1152,7 +979,7 @@ static char *guess_ref(const char *name, struct ref *peer) } static int match_explicit_lhs(struct ref *src, - struct refspec *rs, + struct refspec_item *rs, struct ref **match, int *allocated_match) { @@ -1178,7 +1005,7 @@ static int match_explicit_lhs(struct ref *src, static int match_explicit(struct ref *src, struct ref *dst, struct ref ***dst_tail, - struct refspec *rs) + struct refspec_item *rs) { struct ref *matched_src, *matched_dst; int allocated_src; @@ -1247,36 +1074,37 @@ static int match_explicit(struct ref *src, struct ref *dst, } static int match_explicit_refs(struct ref *src, struct ref *dst, - struct ref ***dst_tail, struct refspec *rs, - int rs_nr) + struct ref ***dst_tail, struct refspec *rs) { int i, errs; - for (i = errs = 0; i < rs_nr; i++) - errs += match_explicit(src, dst, dst_tail, &rs[i]); + for (i = errs = 0; i < rs->nr; i++) + errs += match_explicit(src, dst, dst_tail, &rs->items[i]); return errs; } -static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref, - int send_mirror, int direction, const struct refspec **ret_pat) +static char *get_ref_match(const struct refspec *rs, const struct ref *ref, + int send_mirror, int direction, + const struct refspec_item **ret_pat) { - const struct refspec *pat; + const struct refspec_item *pat; char *name; int i; int matching_refs = -1; - for (i = 0; i < rs_nr; i++) { - if (rs[i].matching && - (matching_refs == -1 || rs[i].force)) { + for (i = 0; i < rs->nr; i++) { + const struct refspec_item *item = &rs->items[i]; + if (item->matching && + (matching_refs == -1 || item->force)) { matching_refs = i; continue; } - if (rs[i].pattern) { - const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src; + if (item->pattern) { + const char *dst_side = item->dst ? item->dst : item->src; int match; if (direction == FROM_SRC) - match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name); + match = match_name_with_pattern(item->src, ref->name, dst_side, &name); else - match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name); + match = match_name_with_pattern(dst_side, ref->name, item->src, &name); if (match) { matching_refs = i; break; @@ -1286,7 +1114,7 @@ static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref if (matching_refs == -1) return NULL; - pat = rs + matching_refs; + pat = &rs->items[matching_refs]; if (pat->matching) { /* * "matching refs"; traditionally we pushed everything @@ -1361,7 +1189,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds continue; /* not a tag */ if (string_list_has_string(&dst_tag, ref->name)) continue; /* they already have it */ - if (sha1_object_info(ref->new_oid.hash, NULL) != OBJ_TAG) + if (oid_object_info(the_repository, &ref->new_oid, NULL) != OBJ_TAG) continue; /* be conservative */ item = string_list_append(&src_tag, ref->name); item->util = ref; @@ -1428,22 +1256,20 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref) * but we can catch some errors early before even talking to the * remote side. */ -int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) +int check_push_refs(struct ref *src, struct refspec *rs) { - struct refspec *refspec = parse_push_refspec(nr_refspec, refspec_names); int ret = 0; int i; - for (i = 0; i < nr_refspec; i++) { - struct refspec *rs = refspec + i; + for (i = 0; i < rs->nr; i++) { + struct refspec_item *item = &rs->items[i]; - if (rs->pattern || rs->matching) + if (item->pattern || item->matching) continue; - ret |= match_explicit_lhs(src, rs, NULL, NULL); + ret |= match_explicit_lhs(src, item, NULL, NULL); } - free_refspec(nr_refspec, refspec); return ret; } @@ -1456,32 +1282,29 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) * dst (e.g. pushing to a new branch, done in match_explicit_refs). */ int match_push_refs(struct ref *src, struct ref **dst, - int nr_refspec, const char **refspec, int flags) + struct refspec *rs, int flags) { - struct refspec *rs; int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; int send_prune = flags & MATCH_REFS_PRUNE; int errs; - static const char *default_refspec[] = { ":", NULL }; struct ref *ref, **dst_tail = tail_ref(dst); struct string_list dst_ref_index = STRING_LIST_INIT_NODUP; - if (!nr_refspec) { - nr_refspec = 1; - refspec = default_refspec; - } - rs = parse_push_refspec(nr_refspec, (const char **) refspec); - errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec); + /* If no refspec is provided, use the default ":" */ + if (!rs->nr) + refspec_append(rs, ":"); + + errs = match_explicit_refs(src, *dst, &dst_tail, rs); /* pick the remainder */ for (ref = src; ref; ref = ref->next) { struct string_list_item *dst_item; struct ref *dst_peer; - const struct refspec *pat = NULL; + const struct refspec_item *pat = NULL; char *dst_name; - dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat); + dst_name = get_ref_match(rs, ref, send_mirror, FROM_SRC, &pat); if (!dst_name) continue; @@ -1530,7 +1353,7 @@ int match_push_refs(struct ref *src, struct ref **dst, /* We're already sending something to this ref. */ continue; - src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL); + src_name = get_ref_match(rs, ref, send_mirror, FROM_DST, NULL); if (src_name) { if (!src_ref_index.nr) prepare_ref_index(&src_ref_index, src); @@ -1542,6 +1365,7 @@ int match_push_refs(struct ref *src, struct ref **dst, } string_list_clear(&src_ref_index, 0); } + if (errs) return -1; return 0; @@ -1738,7 +1562,7 @@ static const char *tracking_for_push_dest(struct remote *remote, { char *ret; - ret = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); + ret = apply_refspecs(&remote->fetch, refname); if (!ret) return error_buf(err, _("push destination '%s' on remote '%s' has no local tracking branch"), @@ -1756,12 +1580,11 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err) _("branch '%s' has no remote for pushing"), branch->name); - if (remote->push_refspec_nr) { + if (remote->push.nr) { char *dst; const char *ret; - dst = apply_refspecs(remote->push, remote->push_refspec_nr, - branch->refname); + dst = apply_refspecs(&remote->push, branch->refname); if (!dst) return error_buf(err, _("push refspecs for '%s' do not include '%s'"), @@ -1804,7 +1627,7 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err) } } - die("BUG: unhandled push situation"); + BUG("unhandled push situation"); } const char *branch_get_push(struct branch *branch, struct strbuf *err) @@ -1834,7 +1657,7 @@ static int ignore_symref_update(const char *refname) * local symbolic ref. */ static struct ref *get_expanded_map(const struct ref *remote_refs, - const struct refspec *refspec) + const struct refspec_item *refspec) { const struct ref *ref; struct ref *ret = NULL; @@ -1899,7 +1722,7 @@ static struct ref *get_local_ref(const char *name) } int get_fetch_map(const struct ref *remote_refs, - const struct refspec *refspec, + const struct refspec_item *refspec, struct ref ***tail, int missing_ok) { @@ -1970,33 +1793,33 @@ static void unmark_and_free(struct commit_list *list, unsigned int mark) int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid) { struct object *o; - struct commit *old, *new; + struct commit *old_commit, *new_commit; struct commit_list *list, *used; int found = 0; /* - * Both new and old must be commit-ish and new is descendant of - * old. Otherwise we require --force. + * Both new_commit and old_commit must be commit-ish and new_commit is descendant of + * old_commit. Otherwise we require --force. */ o = deref_tag(parse_object(old_oid), NULL, 0); if (!o || o->type != OBJ_COMMIT) return 0; - old = (struct commit *) o; + old_commit = (struct commit *) o; o = deref_tag(parse_object(new_oid), NULL, 0); if (!o || o->type != OBJ_COMMIT) return 0; - new = (struct commit *) o; + new_commit = (struct commit *) o; - if (parse_commit(new) < 0) + if (parse_commit(new_commit) < 0) return 0; used = list = NULL; - commit_list_insert(new, &list); + commit_list_insert(new_commit, &list); while (list) { - new = pop_most_recent_commit(&list, TMP_MARK); - commit_list_insert(new, &used); - if (new == old) { + new_commit = pop_most_recent_commit(&list, TMP_MARK); + commit_list_insert(new_commit, &used); + if (new_commit == old_commit) { found = 1; break; } @@ -2007,16 +1830,23 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid) } /* - * Compare a branch with its upstream, and save their differences (number - * 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. + * Lookup the upstream branch for the given branch and if present, optionally + * compute the commit ahead/behind values for the pair. + * + * If abf is AHEAD_BEHIND_FULL, compute the full ahead/behind and return the + * counts in *num_ours and *num_theirs. If abf is AHEAD_BEHIND_QUICK, skip + * the (potentially expensive) a/b computation (*num_ours and *num_theirs are + * set to zero). + * + * The name of the upstream branch (or NULL if no upstream is defined) is + * returned via *upstream_name, if it is not itself NULL. * * 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. + * upstream defined, or ref does not exist). Returns 0 if the commits are + * identical. Returns 1 if commits are different. */ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, - const char **upstream_name) + const char **upstream_name, enum ahead_behind_flags abf) { struct object_id oid; struct commit *ours, *theirs; @@ -2044,11 +1874,15 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, if (!ours) return -1; + *num_theirs = *num_ours = 0; + /* are we the same? */ - if (theirs == ours) { - *num_theirs = *num_ours = 0; + if (theirs == ours) return 0; - } + if (abf == AHEAD_BEHIND_QUICK) + return 1; + if (abf != AHEAD_BEHIND_FULL) + BUG("stat_tracking_info: invalid abf '%d'", abf); /* Run "rev-list --left-right ours...theirs" internally... */ argv_array_push(&argv, ""); /* ignored */ @@ -2064,8 +1898,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, die("revision walk setup failed"); /* ... and count the commits on each side. */ - *num_ours = 0; - *num_theirs = 0; while (1) { struct commit *c = get_revision(&revs); if (!c) @@ -2081,20 +1913,22 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs, clear_commit_marks(theirs, ALL_REV_FLAGS); argv_array_clear(&argv); - return 0; + return 1; } /* * Return true when there is anything to report, otherwise false. */ -int format_tracking_info(struct branch *branch, struct strbuf *sb) +int format_tracking_info(struct branch *branch, struct strbuf *sb, + enum ahead_behind_flags abf) { - int ours, theirs; + int ours, theirs, sti; const char *full_base; char *base; int upstream_is_gone = 0; - if (stat_tracking_info(branch, &ours, &theirs, &full_base) < 0) { + sti = stat_tracking_info(branch, &ours, &theirs, &full_base, abf); + if (sti < 0) { if (!full_base) return 0; upstream_is_gone = 1; @@ -2108,10 +1942,17 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) if (advice_status_hints) strbuf_addstr(sb, _(" (use \"git branch --unset-upstream\" to fixup)\n")); - } else if (!ours && !theirs) { + } else if (!sti) { strbuf_addf(sb, _("Your branch is up to date with '%s'.\n"), base); + } else if (abf == AHEAD_BEHIND_QUICK) { + strbuf_addf(sb, + _("Your branch and '%s' refer to different commits.\n"), + base); + if (advice_status_hints) + strbuf_addf(sb, _(" (use \"%s\" for details)\n"), + "git status --ahead-behind"); } else if (!theirs) { strbuf_addf(sb, Q_("Your branch is ahead of '%s' by %d commit.\n", @@ -2219,8 +2060,7 @@ struct ref *guess_remote_head(const struct ref *head, struct stale_heads_info { struct string_list *ref_names; struct ref **stale_refs_tail; - struct refspec *refs; - int ref_count; + struct refspec *rs; }; static int get_stale_heads_cb(const char *refname, const struct object_id *oid, @@ -2228,12 +2068,12 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid, { struct stale_heads_info *info = cb_data; struct string_list matches = STRING_LIST_INIT_DUP; - struct refspec query; + struct refspec_item query; int i, stale = 1; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.dst = (char *)refname; - query_refspecs_multiple(info->refs, info->ref_count, &query, &matches); + query_refspecs_multiple(info->rs, &query, &matches); if (matches.nr == 0) goto clean_exit; /* No matches */ @@ -2261,7 +2101,7 @@ clean_exit: return 0; } -struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map) +struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map) { struct ref *ref, *stale_refs = NULL; struct string_list ref_names = STRING_LIST_INIT_NODUP; @@ -2269,8 +2109,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet info.ref_names = &ref_names; info.stale_refs_tail = &stale_refs; - info.refs = refs; - info.ref_count = ref_count; + info.rs = rs; for (ref = fetch_map; ref; ref = ref->next) string_list_append(&ref_names, ref->name); string_list_sort(&ref_names); @@ -2354,7 +2193,7 @@ static int remote_tracking(struct remote *remote, const char *refname, { char *dst; - dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); + dst = apply_refspecs(&remote->fetch, refname); if (!dst) return -1; /* no tracking ref for refname at remote */ if (read_ref(dst, oid)) |