From: Jeff Hostetler <jeffhost@xxxxxxxxxxxxx> Extend stat_tracking_info() to return +1 when branches are not equal and to take a new "enum ahead_behind_flags" argument to allow skipping the (possibly expensive) ahead/behind computation. This will be used in the next commit to allow "git status" to avoid full ahead/behind calculations for performance reasons. Signed-off-by: Jeff Hostetler <jeffhost@xxxxxxxxxxxxx> --- ref-filter.c | 8 ++++---- remote.c | 34 +++++++++++++++++++++------------- remote.h | 8 +++++++- wt-status.c | 6 ++++-- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/ref-filter.c b/ref-filter.c index e728b15..23bcdc4 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1238,8 +1238,8 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname, if (atom->u.remote_ref.option == RR_REF) *s = show_ref(&atom->u.remote_ref.refname, refname); else if (atom->u.remote_ref.option == RR_TRACK) { - if (stat_tracking_info(branch, &num_ours, - &num_theirs, NULL)) { + if (stat_tracking_info(branch, &num_ours, &num_theirs, + NULL, AHEAD_BEHIND_FULL) < 0) { *s = xstrdup(msgs.gone); } else if (!num_ours && !num_theirs) *s = ""; @@ -1256,8 +1256,8 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname, free((void *)to_free); } } else if (atom->u.remote_ref.option == RR_TRACKSHORT) { - if (stat_tracking_info(branch, &num_ours, - &num_theirs, NULL)) + if (stat_tracking_info(branch, &num_ours, &num_theirs, + NULL, AHEAD_BEHIND_FULL) < 0) return; if (!num_ours && !num_theirs) diff --git a/remote.c b/remote.c index b220f0d..23177f5 100644 --- a/remote.c +++ b/remote.c @@ -1977,16 +1977,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; @@ -2014,11 +2021,13 @@ 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; /* Run "rev-list --left-right ours...theirs" internally... */ argv_array_push(&argv, ""); /* ignored */ @@ -2034,8 +2043,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) @@ -2051,7 +2058,7 @@ 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; } /* @@ -2064,7 +2071,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) char *base; int upstream_is_gone = 0; - if (stat_tracking_info(branch, &ours, &theirs, &full_base) < 0) { + if (stat_tracking_info(branch, &ours, &theirs, &full_base, + AHEAD_BEHIND_FULL) < 0) { if (!full_base) return 0; upstream_is_gone = 1; diff --git a/remote.h b/remote.h index 2ecf4c8..00932f5 100644 --- a/remote.h +++ b/remote.h @@ -255,9 +255,15 @@ enum match_refs_flags { MATCH_REFS_FOLLOW_TAGS = (1 << 3) }; +/* Flags for --ahead-behind option. */ +enum ahead_behind_flags { + AHEAD_BEHIND_QUICK = 0, /* just eq/neq reporting */ + AHEAD_BEHIND_FULL = 1, /* traditional a/b reporting */ +}; + /* Reporting of tracking info */ 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); int format_tracking_info(struct branch *branch, struct strbuf *sb); struct ref *get_local_heads(void); diff --git a/wt-status.c b/wt-status.c index 94e5eba..8f7fdc6 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1791,7 +1791,8 @@ static void wt_shortstatus_print_tracking(struct wt_status *s) color_fprintf(s->fp, branch_color_local, "%s", branch_name); - if (stat_tracking_info(branch, &num_ours, &num_theirs, &base) < 0) { + if (stat_tracking_info(branch, &num_ours, &num_theirs, &base, + AHEAD_BEHIND_FULL) < 0) { if (!base) goto conclude; @@ -1928,7 +1929,8 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s) /* Lookup stats on the upstream tracking branch, if set. */ branch = branch_get(branch_name); base = NULL; - ab_info = (stat_tracking_info(branch, &nr_ahead, &nr_behind, &base) == 0); + ab_info = (stat_tracking_info(branch, &nr_ahead, &nr_behind, + &base, AHEAD_BEHIND_FULL) >= 0); if (base) { base = shorten_unambiguous_ref(base, 0); fprintf(s->fp, "# branch.upstream %s%c", base, eol); -- 2.9.3