summaryrefslogtreecommitdiff
path: root/remote.c
diff options
context:
space:
mode:
Diffstat (limited to 'remote.c')
-rw-r--r--remote.c419
1 files changed, 129 insertions, 290 deletions
diff --git a/remote.c b/remote.c
index 4e93753..539285f 100644
--- a/remote.c
+++ b/remote.c
@@ -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))