{"thread":{"id":"47478","subject":"[PATCH v2 0/5] Add --no-ahead-behind to status","startedAt":"2017-12-21T19:09:22Z","lastAt":"2018-04-03T13:47:32Z","messageCount":20,"participants":["Jeff Hostetler","Igor Djordjevic","Jonathan Nieder","Junio C Hamano","Jeff King","Lars Schneider","Ævar Arnfjörð Bjarmason","Derrick Stolee"],"isPatch":true,"patchVersion":2,"patchTotal":5},"messages":[{"id":"335138","messageId":"20171221190909.62995-1-git@jeffhostetler.com","threadId":"47478","inReplyTo":null,"subject":"[PATCH v2 0/5] Add --no-ahead-behind to status","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-21T19:09:04Z","receivedAt":"2017-12-21T19:09:22Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nThis is version 2 of my patch series to avoid expensive\nahead/behind calculations in status.  This version addresses\nPeff's comments on V1.\n\nThis version renames the command line parameter to have\npositive sense \"--ahead-behind\" and avoids confusing double\nnegatives throughout.  It also changes the config setting\nfrom \"status.\" to \"core.\" in anticipation of use by other\ncommands (like branch and checkout).\n\nThe output for porcelain status formats does change, but\nONLY if the \"--no-ahead-behind\" option is given on the\ncommand line; porcelain formats DO NOT inherit the config\nsetting.  The intent here is that only scripts explicitly\nrequesting the new feature will see any format changes.\n\nThis idea was previously discussed in [1].  Working with the\nenormous Windows repository, we found that 20+ seconds was being\nspent in the ahead/behind computation when the current branch was\n150K commits behind the upstream branch.  (Yes, this happens and\nonly took 3 weeks on the reporter's system.)\n\n\nI've only modified \"git status\" in this patch series.  A similar\nchange could be added to \"git branch -vv\" and \"git checkout\" to\navoid delays there too.  I avoided doing it here to keep this\npatch series focused.\n\n[1] https://public-inbox.org/git/030bf57c-7a23-3391-4fc0-93efee791543@jeffhostetler.com/T/\n\nJeff Hostetler (5):\n  core.aheadbehind: add new config setting\n  stat_tracking_info: return +1 when branches are not equal\n  status: add --[no-]ahead-behind to porcelain V2 output\n  status: update short status to use --no-ahead-behind\n  status: support --no-ahead-behind in long format\n\n Documentation/config.txt     |  8 ++++++\n Documentation/git-status.txt | 11 ++++++--\n builtin/checkout.c           |  2 +-\n builtin/commit.c             | 19 ++++++++++++++\n cache.h                      |  1 +\n config.c                     |  5 ++++\n environment.c                |  1 +\n ref-filter.c                 |  4 +--\n remote.c                     | 38 ++++++++++++++++++++--------\n remote.h                     | 10 ++++++--\n t/t6040-tracking-info.sh     | 42 +++++++++++++++++++++++++++++++\n t/t7064-wtstatus-pv2.sh      | 60 ++++++++++++++++++++++++++++++++++++++++++++\n wt-status.c                  | 34 +++++++++++++++++++------\n wt-status.h                  |  2 ++\n 14 files changed, 212 insertions(+), 25 deletions(-)\n\n-- \n2.9.3\n\n"},{"id":"335139","messageId":"20171221190909.62995-2-git@jeffhostetler.com","threadId":"47478","inReplyTo":"20171221190909.62995-1-git@jeffhostetler.com","subject":"[PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-21T19:09:05Z","receivedAt":"2017-12-21T19:09:23Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nCreated core.aheadbehind config setting and core_ahead_behind\nglobal variable.  This value defaults to true.\n\nThis value will be used in the next few commits as the default value\nfor the --ahead-behind parameter.\n\nSigned-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n---\n Documentation/config.txt | 8 ++++++++\n cache.h                  | 1 +\n config.c                 | 5 +++++\n environment.c            | 1 +\n 4 files changed, 15 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 9593bfa..c78d6be 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -895,6 +895,14 @@ core.abbrev::\n \tabbreviated object names to stay unique for some time.\n \tThe minimum length is 4.\n \n+core.aheadbehind::\n+\tIf true, tells commands like status and branch to print ahead and\n+\tbehind counts for the branch relative to its upstream branch.\n+\tThis computation may be very expensive when there is a great\n+\tdistance between the two branches.  If false, these commands\n+\tonly print that the two branches refer to different commits.\n+\tDefaults to true.\n+\n add.ignoreErrors::\n add.ignore-errors (deprecated)::\n \tTells 'git add' to continue adding files when some files cannot be\ndiff --git a/cache.h b/cache.h\nindex 6440e2b..5757d8f 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -735,6 +735,7 @@ extern int assume_unchanged;\n extern int prefer_symlink_refs;\n extern int warn_ambiguous_refs;\n extern int warn_on_object_refname_ambiguity;\n+extern int core_ahead_behind;\n extern const char *apply_default_whitespace;\n extern const char *apply_default_ignorewhitespace;\n extern const char *git_attributes_file;\ndiff --git a/config.c b/config.c\nindex c38401a..6a4b49c 100644\n--- a/config.c\n+++ b/config.c\n@@ -1241,6 +1241,11 @@ static int git_default_core_config(const char *var, const char *value)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"core.aheadbehind\")) {\n+\t\tcore_ahead_behind = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \t/* Add other config variables here and to Documentation/config.txt. */\n \treturn 0;\n }\ndiff --git a/environment.c b/environment.c\nindex 8289c25..5822c15 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -25,6 +25,7 @@ int prefer_symlink_refs;\n int is_bare_repository_cfg = -1; /* unspecified */\n int warn_ambiguous_refs = 1;\n int warn_on_object_refname_ambiguity = 1;\n+int core_ahead_behind = 1;\n int ref_paranoia = -1;\n int repository_format_precious_objects;\n const char *git_commit_encoding;\n-- \n2.9.3\n\n"},{"id":"335140","messageId":"20171221190909.62995-4-git@jeffhostetler.com","threadId":"47478","inReplyTo":"20171221190909.62995-1-git@jeffhostetler.com","subject":"[PATCH v2 3/5] status: add --[no-]ahead-behind to porcelain V2 output","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-21T19:09:07Z","receivedAt":"2017-12-21T19:09:27Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nTeach \"status --porcelain=v2 --branch\" to omit detailed ahead/behind\ninformation when \"--no-ahead-behind\" argument is used.\n\nWhen \"--no-ahead-behind\" is given, the existing \"branch.ab x y\" line\nis replaced with a new \"branch.qab eq|neq\" line.\n\nThis allows the user to omit the (possibly extremely expensive)\nahead/behind computation when not wanted.  In its place, a single\nequal/not-equal line is reported.\n\nSigned-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n---\n Documentation/git-status.txt | 11 ++++++--\n builtin/commit.c             | 19 ++++++++++++++\n t/t7064-wtstatus-pv2.sh      | 60 ++++++++++++++++++++++++++++++++++++++++++++\n wt-status.c                  | 24 ++++++++++++++----\n wt-status.h                  |  2 ++\n 5 files changed, 109 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-status.txt b/Documentation/git-status.txt\nindex 9f3a78a..d0e5f89 100644\n--- a/Documentation/git-status.txt\n+++ b/Documentation/git-status.txt\n@@ -111,6 +111,12 @@ configuration variable documented in linkgit:git-config[1].\n \twithout options are equivalent to 'always' and 'never'\n \trespectively.\n \n+--ahead-behind::\n+--no-ahead-behind::\n+\tDisplay or do not display detailed ahead/behind counts for the branch\n+\trelative to its upstream branch.  Defaults to true.  Overrides the\n+\tvalue of \"core.aheadbehind\".\n+\n <pathspec>...::\n \tSee the 'pathspec' entry in linkgit:gitglossary[7].\n \n@@ -242,7 +248,8 @@ don't recognize.\n ### Branch Headers\n \n If `--branch` is given, a series of header lines are printed with\n-information about the current branch.\n+information about the current branch.  If `--no-ahead-behind` is given,\n+the branch.ab line is replaced with the branch.qab line.\n \n     Line                                     Notes\n     ------------------------------------------------------------\n@@ -250,7 +257,7 @@ information about the current branch.\n     # branch.head <branch> | (detached)      Current branch.\n     # branch.upstream <upstream_branch>      If upstream is set.\n     # branch.ab +<ahead> -<behind>           If upstream is set and\n-\t\t\t\t\t     the commit is present.\n+    # branch.qab eq | neq                    the commit is present.\n     ------------------------------------------------------------\n \n ### Changed Tracked Entries\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex be370f6..d6e2717 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -141,6 +141,7 @@ static int sequencer_in_use;\n static int use_editor = 1, include_status = 1;\n static int show_ignored_in_status, have_option_m;\n static struct strbuf message = STRBUF_INIT;\n+static int ahead_behind_opt = -1;\n \n static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;\n \n@@ -1369,6 +1370,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\t  N_(\"ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)\"),\n \t\t  PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n \t\tOPT_COLUMN(0, \"column\", &s.colopts, N_(\"list untracked files in columns\")),\n+\t\tOPT_BOOL(0, \"ahead-behind\", &ahead_behind_opt,\n+\t\t\t N_(\"compute branch ahead/behind values\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1389,6 +1392,21 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\t       PATHSPEC_PREFER_FULL,\n \t\t       prefix, argv);\n \n+\t/*\n+\t * Porcelain formats only look at the --[no-]ahead-behind command\n+\t * line argument and DO NOT look at the config setting.  Non-porcelain\n+\t * formats use both.\n+\t */\n+\tif (status_format == STATUS_FORMAT_PORCELAIN ||\n+\t    status_format == STATUS_FORMAT_PORCELAIN_V2) {\n+\t\tif (ahead_behind_opt < 0)\n+\t\t\tahead_behind_opt = ABF_FULL;\n+\t} else {\n+\t\tif (ahead_behind_opt < 0)\n+\t\t\tahead_behind_opt = core_ahead_behind;\n+\t}\n+\ts.ab_flags = ((ahead_behind_opt) ? ABF_FULL : ABF_QUICK);\n+\n \tread_cache_preload(&s.pathspec);\n \trefresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);\n \n@@ -1667,6 +1685,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \ts.commit_template = 1;\n \tstatus_format = STATUS_FORMAT_NONE; /* Ignore status.short */\n \ts.colopts = 0;\n+\ts.ab_flags = core_ahead_behind;\n \n \tif (get_oid(\"HEAD\", &oid))\n \t\tcurrent_head = NULL;\ndiff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh\nindex e319fa2..e132183 100755\n--- a/t/t7064-wtstatus-pv2.sh\n+++ b/t/t7064-wtstatus-pv2.sh\n@@ -390,6 +390,66 @@ test_expect_success 'verify upstream fields in branch header' '\n \t)\n '\n \n+test_expect_success 'verify --no-ahead-behind generates branch.qab' '\n+\tgit checkout master &&\n+\ttest_when_finished \"rm -rf sub_repo\" &&\n+\tgit clone . sub_repo &&\n+\t(\n+\t\t## Confirm local master tracks remote master.\n+\t\tcd sub_repo &&\n+\t\tHUF=$(git rev-parse HEAD) &&\n+\n+\t\tcat >expect <<-EOF &&\n+\t\t# branch.oid $HUF\n+\t\t# branch.head master\n+\t\t# branch.upstream origin/master\n+\t\t# branch.qab eq\n+\t\tEOF\n+\n+\t\tgit status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&\n+\t\ttest_cmp expect actual &&\n+\n+\t\tcat >expect <<-EOF &&\n+\t\t# branch.oid $HUF\n+\t\t# branch.head master\n+\t\t# branch.upstream origin/master\n+\t\t# branch.ab +0 -0\n+\t\tEOF\n+\n+\t\t# V2 does not use the config setting, only the command line argument.\n+\t\tgit -c core.aheadbehind=false status --porcelain=v2 --branch --untracked-files=all >actual &&\n+\t\ttest_cmp expect actual\n+\n+\t\t## Test ahead/behind.\n+\t\techo xyz >file_xyz &&\n+\t\tgit add file_xyz &&\n+\t\tgit commit -m xyz &&\n+\n+\t\tHUF=$(git rev-parse HEAD) &&\n+\n+\t\tcat >expect <<-EOF &&\n+\t\t# branch.oid $HUF\n+\t\t# branch.head master\n+\t\t# branch.upstream origin/master\n+\t\t# branch.qab neq\n+\t\tEOF\n+\n+\t\tgit status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&\n+\t\ttest_cmp expect actual &&\n+\n+\t\tcat >expect <<-EOF &&\n+\t\t# branch.oid $HUF\n+\t\t# branch.head master\n+\t\t# branch.upstream origin/master\n+\t\t# branch.ab +1 -0\n+\t\tEOF\n+\n+\t\t# V2 does not use the config setting, only the command line argument.\n+\t\tgit -c core.aheadbehind=false status --porcelain=v2 --branch --untracked-files=all >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n test_expect_success 'create and add submodule, submodule appears clean (A. S...)' '\n \tgit checkout master &&\n \tgit clone . sub_repo &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 80c23ba..d03b47a 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1867,6 +1867,12 @@ static void wt_porcelain_print(struct wt_status *s)\n  *   [# branch.upstream <upstream><eol>\n  *   [# branch.ab +<ahead> -<behind><eol>]]\n  *\n+ * When the '--no-ahead-behind' parameter is given and an upstream\n+ * is set and present, the branch.ab line is omitted and the following\n+ * line is added (for quick ahead/behind):\n+ *\n+ *   [# branch.qab <equal><eol>]\n+ *\n  *      <commit> ::= the current commit hash or the the literal\n  *                   \"(initial)\" to indicate an initialized repo\n  *                   with no commits.\n@@ -1883,6 +1889,8 @@ static void wt_porcelain_print(struct wt_status *s)\n  *      <behind> ::= integer behind value, when upstream set\n  *                   and commit is present.\n  *\n+ *       <equal> ::= literal string \"eq\" or \"neq\".\n+ *\n  *\n  * The end-of-line is defined by the -z flag.\n  *\n@@ -1896,7 +1904,7 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)\n \tconst char *base;\n \tconst char *branch_name;\n \tstruct wt_status_state state;\n-\tint have_ab_info, nr_ahead, nr_behind;\n+\tint nr_ahead, nr_behind, sti;\n \tchar eol = s->null_termination ? '\\0' : '\\n';\n \n \tmemset(&state, 0, sizeof(state));\n@@ -1928,15 +1936,21 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)\n \t\t/* Lookup stats on the upstream tracking branch, if set. */\n \t\tbranch = branch_get(branch_name);\n \t\tbase = NULL;\n-\t\thave_ab_info = (stat_tracking_info(branch, &nr_ahead,\n-\t\t\t\t\t\t   &nr_behind, &base, ABF_FULL) >= 0);\n+\t\tsti = stat_tracking_info(branch, &nr_ahead, &nr_behind, &base,\n+\t\t\t\t\t s->ab_flags);\n \t\tif (base) {\n \t\t\tbase = shorten_unambiguous_ref(base, 0);\n \t\t\tfprintf(s->fp, \"# branch.upstream %s%c\", base, eol);\n \t\t\tfree((char *)base);\n \n-\t\t\tif (have_ab_info)\n-\t\t\t\tfprintf(s->fp, \"# branch.ab +%d -%d%c\", nr_ahead, nr_behind, eol);\n+\t\t\tif (sti >= 0) {\n+\t\t\t\tif (s->ab_flags == ABF_FULL)\n+\t\t\t\t\tfprintf(s->fp, \"# branch.ab +%d -%d%c\",\n+\t\t\t\t\t\tnr_ahead, nr_behind, eol);\n+\t\t\t\telse\n+\t\t\t\t\tfprintf(s->fp, \"# branch.qab %s%c\",\n+\t\t\t\t\t\t(sti ? \"neq\" : \"eq\"), eol);\n+\t\t\t}\n \t\t}\n \t}\n \ndiff --git a/wt-status.h b/wt-status.h\nindex 64f4d33..5075d95 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -5,6 +5,7 @@\n #include \"string-list.h\"\n #include \"color.h\"\n #include \"pathspec.h\"\n+#include \"remote.h\"\n \n struct worktree;\n \n@@ -80,6 +81,7 @@ struct wt_status {\n \tint show_branch;\n \tint show_stash;\n \tint hints;\n+\tenum ahead_behind_flags ab_flags;\n \n \tenum wt_status_format status_format;\n \tunsigned char sha1_commit[GIT_MAX_RAWSZ]; /* when not Initial */\n-- \n2.9.3\n\n"},{"id":"335141","messageId":"20171221190909.62995-5-git@jeffhostetler.com","threadId":"47478","inReplyTo":"20171221190909.62995-1-git@jeffhostetler.com","subject":"[PATCH v2 4/5] status: update short status to use --no-ahead-behind","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-21T19:09:08Z","receivedAt":"2017-12-21T19:09:29Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nTeach \"git status --short --branch\" to use \"--no-ahead-behind\"\nflag to skip computing ahead/behind counts for the branch and\nits upstream and just report '[different]'.\n\nSigned-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n---\n t/t6040-tracking-info.sh | 13 +++++++++++++\n wt-status.c              |  9 ++++++---\n 2 files changed, 19 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 8f17fd9..0190220 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -147,6 +147,19 @@ test_expect_success 'status -s -b (diverged from upstream)' '\n '\n \n cat >expect <<\\EOF\n+## b1...origin/master [different]\n+EOF\n+\n+test_expect_success 'status -s -b --no-ahead-behind (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b --no-ahead-behind | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n ## b5...brokenbase [gone]\n EOF\n \ndiff --git a/wt-status.c b/wt-status.c\nindex d03b47a..3235ec2 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1765,7 +1765,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tconst char *base;\n \tchar *short_base;\n \tconst char *branch_name;\n-\tint num_ours, num_theirs;\n+\tint num_ours, num_theirs, sti;\n \tint upstream_is_gone = 0;\n \n \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"## \");\n@@ -1791,7 +1791,8 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \n \tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \n-\tif (stat_tracking_info(branch, &num_ours, &num_theirs, &base, ABF_FULL) < 0) {\n+\tsti = stat_tracking_info(branch, &num_ours, &num_theirs, &base, s->ab_flags);\n+\tif (sti < 0) {\n \t\tif (!base)\n \t\t\tgoto conclude;\n \n@@ -1803,12 +1804,14 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", short_base);\n \tfree(short_base);\n \n-\tif (!upstream_is_gone && !num_ours && !num_theirs)\n+\tif (!upstream_is_gone && !sti)\n \t\tgoto conclude;\n \n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (upstream_is_gone) {\n \t\tcolor_fprintf(s->fp, header_color, LABEL(N_(\"gone\")));\n+\t} else if (s->ab_flags == ABF_QUICK) {\n+\t\tcolor_fprintf(s->fp, header_color, LABEL(N_(\"different\")));\n \t} else if (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, LABEL(N_(\"behind \")));\n \t\tcolor_fprintf(s->fp, branch_color_remote, \"%d\", num_theirs);\n-- \n2.9.3\n\n"},{"id":"335142","messageId":"20171221190909.62995-6-git@jeffhostetler.com","threadId":"47478","inReplyTo":"20171221190909.62995-1-git@jeffhostetler.com","subject":"[PATCH v2 5/5] status: support --no-ahead-behind in long format","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-21T19:09:09Z","receivedAt":"2017-12-21T19:09:31Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nTeach long (normal) status format to respect the --no-ahead-behind\nargument and skip the possibly expensive ahead/behind computation\nbetween the branch and the upstream.\n\nSigned-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n---\n builtin/checkout.c       |  2 +-\n remote.c                 | 16 +++++++++++++---\n remote.h                 |  3 ++-\n t/t6040-tracking-info.sh | 29 +++++++++++++++++++++++++++++\n wt-status.c              |  2 +-\n 5 files changed, 46 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex fc4f8fd..b005139 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -605,7 +605,7 @@ static void report_tracking(struct branch_info *new)\n \tstruct strbuf sb = STRBUF_INIT;\n \tstruct branch *branch = branch_get(new->name);\n \n-\tif (!format_tracking_info(branch, &sb))\n+\tif (!format_tracking_info(branch, &sb, ABF_FULL))\n \t\treturn;\n \tfputs(sb.buf, stdout);\n \tstrbuf_release(&sb);\ndiff --git a/remote.c b/remote.c\nindex 91b5afb..76fa96c 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -2065,14 +2065,17 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,\n /*\n  * Return true when there is anything to report, otherwise false.\n  */\n-int format_tracking_info(struct branch *branch, struct strbuf *sb)\n+int format_tracking_info(struct branch *branch, struct strbuf *sb,\n+\t\t\t enum ahead_behind_flags abf)\n {\n \tint ours, theirs;\n \tconst char *full_base;\n \tchar *base;\n \tint upstream_is_gone = 0;\n+\tint sti;\n \n-\tif (stat_tracking_info(branch, &ours, &theirs, &full_base, ABF_FULL) < 0) {\n+\tsti = stat_tracking_info(branch, &ours, &theirs, &full_base, abf);\n+\tif (sti < 0) {\n \t\tif (!full_base)\n \t\t\treturn 0;\n \t\tupstream_is_gone = 1;\n@@ -2086,10 +2089,17 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addstr(sb,\n \t\t\t\t_(\"  (use \\\"git branch --unset-upstream\\\" to fixup)\\n\"));\n-\t} else if (!ours && !theirs) {\n+\t} else if (!sti) {\n \t\tstrbuf_addf(sb,\n \t\t\t_(\"Your branch is up to date with '%s'.\\n\"),\n \t\t\tbase);\n+\t} else if (abf == ABF_QUICK) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t    _(\"Your branch and '%s' refer to different commits.\\n\"),\n+\t\t\t    base);\n+\t\tif (advice_status_hints)\n+\t\t\tstrbuf_addf(sb, _(\"  (use \\\"%s\\\" for details)\\n\"),\n+\t\t\t\t    \"git status --ahead-behind\");\n \t} else if (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\ndiff --git a/remote.h b/remote.h\nindex 1e12dfb..33f88de 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -263,7 +263,8 @@ enum ahead_behind_flags {\n /* Reporting of tracking info */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,\n \t\t       const char **upstream_name, enum ahead_behind_flags abf);\n-int format_tracking_info(struct branch *branch, struct strbuf *sb);\n+int format_tracking_info(struct branch *branch, struct strbuf *sb,\n+\t\t\t enum ahead_behind_flags abf);\n \n struct ref *get_local_heads(void);\n /*\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 0190220..716283b 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -160,6 +160,35 @@ test_expect_success 'status -s -b --no-ahead-behind (diverged from upstream)' '\n '\n \n cat >expect <<\\EOF\n+On branch b1\n+Your branch and 'origin/master' have diverged,\n+and have 1 and 1 different commits each, respectively.\n+EOF\n+\n+test_expect_success 'status --long --branch' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status --long -b | head -3\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+On branch b1\n+Your branch and 'origin/master' refer to different commits.\n+EOF\n+\n+test_expect_success 'status --long --branch --no-ahead-behind' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status --long -b --no-ahead-behind | head -2\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n ## b5...brokenbase [gone]\n EOF\n \ndiff --git a/wt-status.c b/wt-status.c\nindex 3235ec2..4a4c7b7 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1005,7 +1005,7 @@ static void wt_longstatus_print_tracking(struct wt_status *s)\n \tif (!skip_prefix(s->branch, \"refs/heads/\", &branch_name))\n \t\treturn;\n \tbranch = branch_get(branch_name);\n-\tif (!format_tracking_info(branch, &sb))\n+\tif (!format_tracking_info(branch, &sb, s->ab_flags))\n \t\treturn;\n \n \ti = 0;\n-- \n2.9.3\n\n"},{"id":"335143","messageId":"20171221190909.62995-3-git@jeffhostetler.com","threadId":"47478","inReplyTo":"20171221190909.62995-1-git@jeffhostetler.com","subject":"[PATCH v2 2/5] stat_tracking_info: return +1 when branches are not equal","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2017-12-21T19:09:06Z","receivedAt":"2017-12-21T19:09:34Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"From: Jeff Hostetler <jeffhost@microsoft.com>\n\nExtend stat_tracking_info() return +1 when the branches are not equal\nand to take a new \"enum ahead_behind_flag\" ABF_QUICK to avoid the\nexpensive ahead/behind computation when requested.\n\nSigned-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n---\n ref-filter.c |  4 ++--\n remote.c     | 24 ++++++++++++++++--------\n remote.h     |  7 ++++++-\n wt-status.c  |  9 +++++----\n 4 files changed, 29 insertions(+), 15 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex e728b15..6191cb4 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1239,7 +1239,7 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t*s = show_ref(&atom->u.remote_ref.refname, refname);\n \telse if (atom->u.remote_ref.option == RR_TRACK) {\n \t\tif (stat_tracking_info(branch, &num_ours,\n-\t\t\t\t       &num_theirs, NULL)) {\n+\t\t\t\t       &num_theirs, NULL, ABF_FULL) < 0) {\n \t\t\t*s = xstrdup(msgs.gone);\n \t\t} else if (!num_ours && !num_theirs)\n \t\t\t*s = \"\";\n@@ -1257,7 +1257,7 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n \t\t}\n \t} else if (atom->u.remote_ref.option == RR_TRACKSHORT) {\n \t\tif (stat_tracking_info(branch, &num_ours,\n-\t\t\t\t       &num_theirs, NULL))\n+\t\t\t\t       &num_theirs, NULL, ABF_FULL) < 0)\n \t\t\treturn;\n \n \t\tif (!num_ours && !num_theirs)\ndiff --git a/remote.c b/remote.c\nindex b220f0d..91b5afb 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1977,16 +1977,22 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)\n }\n \n /*\n- * Compare a branch with its upstream, and save their differences (number\n- * of commits) in *num_ours and *num_theirs. The name of the upstream branch\n- * (or NULL if no upstream is defined) is returned via *upstream_name, if it\n- * is not itself NULL.\n+ * Compare a branch with its upstream and report on their differences.\n+ * If abf is ABF_FULL, save their differences (number of commits) in\n+ * *num_ours and *num_theirs.\n+ * If abf is ABF_QUICK, skip the (possibly expensive) ahead/behind\n+ * computation (and leave *num_ours and *num_theirs undefined).\n+ *\n+ * The name of the upstream branch (or NULL if no upstream is defined) is\n+ * returned via *upstream_name, if it is not itself NULL.\n  *\n  * Returns -1 if num_ours and num_theirs could not be filled in (e.g., no\n- * upstream defined, or ref does not exist), 0 otherwise.\n+ * upstream defined, or ref does not exist).\n+ * Returns 0 if the commits are the same.\n+ * Returns 1 if the commits are different (ahead, behind, or both).\n  */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,\n-\t\t       const char **upstream_name)\n+\t\t       const char **upstream_name, enum ahead_behind_flags abf)\n {\n \tstruct object_id oid;\n \tstruct commit *ours, *theirs;\n@@ -2019,6 +2025,8 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,\n \t\t*num_theirs = *num_ours = 0;\n \t\treturn 0;\n \t}\n+\tif (abf == ABF_QUICK)\n+\t\treturn 1;\n \n \t/* Run \"rev-list --left-right ours...theirs\" internally... */\n \targv_array_push(&argv, \"\"); /* ignored */\n@@ -2051,7 +2059,7 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,\n \tclear_commit_marks(theirs, ALL_REV_FLAGS);\n \n \targv_array_clear(&argv);\n-\treturn 0;\n+\treturn 1;\n }\n \n /*\n@@ -2064,7 +2072,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \tchar *base;\n \tint upstream_is_gone = 0;\n \n-\tif (stat_tracking_info(branch, &ours, &theirs, &full_base) < 0) {\n+\tif (stat_tracking_info(branch, &ours, &theirs, &full_base, ABF_FULL) < 0) {\n \t\tif (!full_base)\n \t\t\treturn 0;\n \t\tupstream_is_gone = 1;\ndiff --git a/remote.h b/remote.h\nindex 2ecf4c8..1e12dfb 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -255,9 +255,14 @@ enum match_refs_flags {\n \tMATCH_REFS_FOLLOW_TAGS\t= (1 << 3)\n };\n \n+enum ahead_behind_flags {\n+\tABF_QUICK = 0,  /* just eq/neq reporting */\n+\tABF_FULL  = 1,  /* traditional ahead/behind reporting */\n+};\n+\n /* Reporting of tracking info */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,\n-\t\t       const char **upstream_name);\n+\t\t       const char **upstream_name, enum ahead_behind_flags abf);\n int format_tracking_info(struct branch *branch, struct strbuf *sb);\n \n struct ref *get_local_heads(void);\ndiff --git a/wt-status.c b/wt-status.c\nindex 94e5eba..80c23ba 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1791,7 +1791,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \n \tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \n-\tif (stat_tracking_info(branch, &num_ours, &num_theirs, &base) < 0) {\n+\tif (stat_tracking_info(branch, &num_ours, &num_theirs, &base, ABF_FULL) < 0) {\n \t\tif (!base)\n \t\t\tgoto conclude;\n \n@@ -1896,7 +1896,7 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)\n \tconst char *base;\n \tconst char *branch_name;\n \tstruct wt_status_state state;\n-\tint ab_info, nr_ahead, nr_behind;\n+\tint have_ab_info, nr_ahead, nr_behind;\n \tchar eol = s->null_termination ? '\\0' : '\\n';\n \n \tmemset(&state, 0, sizeof(state));\n@@ -1928,13 +1928,14 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)\n \t\t/* Lookup stats on the upstream tracking branch, if set. */\n \t\tbranch = branch_get(branch_name);\n \t\tbase = NULL;\n-\t\tab_info = (stat_tracking_info(branch, &nr_ahead, &nr_behind, &base) == 0);\n+\t\thave_ab_info = (stat_tracking_info(branch, &nr_ahead,\n+\t\t\t\t\t\t   &nr_behind, &base, ABF_FULL) >= 0);\n \t\tif (base) {\n \t\t\tbase = shorten_unambiguous_ref(base, 0);\n \t\t\tfprintf(s->fp, \"# branch.upstream %s%c\", base, eol);\n \t\t\tfree((char *)base);\n \n-\t\t\tif (ab_info)\n+\t\t\tif (have_ab_info)\n \t\t\t\tfprintf(s->fp, \"# branch.ab +%d -%d%c\", nr_ahead, nr_behind, eol);\n \t\t}\n \t}\n-- \n2.9.3\n\n"},{"id":"335149","messageId":"01040d48-a24e-1146-dcea-29137b1104c9@gmail.com","threadId":"47478","inReplyTo":"20171221190909.62995-2-git@jeffhostetler.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2017-12-21T20:21:13Z","receivedAt":"2017-12-21T20:21:23Z","isPatch":true,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Jeff,\n\nOn 21/12/2017 20:09, Jeff Hostetler wrote:\n> \n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 9593bfa..c78d6be 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -895,6 +895,14 @@ core.abbrev::\n>  \tabbreviated object names to stay unique for some time.\n>  \tThe minimum length is 4.\n>  \n> +core.aheadbehind::\n            ^^^\nA small nitpick - you may want to use \"core.aheadBehind\" throughout \nthe series (note capital \"B\"), making it more readable and aligning \nwith the rest of `git config` variable names (using \"bumpyCaps\" as \nper coding guidelines[1], and as seen at the end of this very patch, \ntoo, \"add.ignoreErrors\").\n\n> +\tIf true, tells commands like status and branch to print ahead and\n> +\tbehind counts for the branch relative to its upstream branch.\n> +\tThis computation may be very expensive when there is a great\n> +\tdistance between the two branches.  If false, these commands\n> +\tonly print that the two branches refer to different commits.\n> +\tDefaults to true.\n> +\n>  add.ignoreErrors::\n>  add.ignore-errors (deprecated)::\n>  \tTells 'git add' to continue adding files when some files cannot be\n\nRegards, Buga\n\n[1] https://github.com/git/git/blob/master/Documentation/CodingGuidelines\n\n  Externally Visible Names\n  \n  ...\n  \n  The section and variable names that consist of multiple words are\n  formed by concatenating the words without punctuations (e.g. `-`),\n  and are broken using bumpyCaps in documentation as a hint to the\n  reader.\n"},{"id":"335150","messageId":"20171221204356.GA58971@aiede.mtv.corp.google.com","threadId":"47478","inReplyTo":"20171221190909.62995-2-git@jeffhostetler.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-12-21T20:43:56Z","receivedAt":"2017-12-21T20:44:07Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nJeff Hostetler wrote:\n\n> Created core.aheadbehind config setting and core_ahead_behind\n> global variable.  This value defaults to true.\n>\n> This value will be used in the next few commits as the default value\n> for the --ahead-behind parameter.\n>\n> Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n> ---\n>  Documentation/config.txt | 8 ++++++++\n>  cache.h                  | 1 +\n>  config.c                 | 5 +++++\n>  environment.c            | 1 +\n>  4 files changed, 15 insertions(+)\n\nNot a reason to reroll on its own, but this seems out of order: the\nseries is easier to explain and easier to merge down in stages if the\npatch for --ahead-behind comes first, then the config setting.\n\nMore generally, new commandline flags tend to be less controversial\nthan new config settings since they cannot affect a script by mistake,\nand for that reason, they can go earlier in the series.\n\nAs a bonus, that makes it possible to include tests.  It's probably\nworth adding a test or two for this new config setting.\n\n[...]\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 9593bfa..c78d6be 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -895,6 +895,14 @@ core.abbrev::\n>  \tabbreviated object names to stay unique for some time.\n>  \tThe minimum length is 4.\n>  \n> +core.aheadbehind::\n> +\tIf true, tells commands like status and branch to print ahead and\n> +\tbehind counts for the branch relative to its upstream branch.\n> +\tThis computation may be very expensive when there is a great\n> +\tdistance between the two branches.  If false, these commands\n> +\tonly print that the two branches refer to different commits.\n> +\tDefaults to true.\n\nThis doesn't seem like a particularly core feature to me.  Should it be\ne.g. status.aheadbehind (even though it also affects \"git branch\") or\neven something like diff.aheadbehind?  I'm not sure.\n\nI also wonder if there's a way to achieve the same benefit without\nhaving it be configurable.  E.g. if a branch is way behind, couldn't\nwe terminate the walk early to get the same bounded cost per branch\nwithout requiring configuration?\n\nThanks,\nJonathan\n"},{"id":"335151","messageId":"20171221204838.GB58971@aiede.mtv.corp.google.com","threadId":"47478","inReplyTo":"20171221190909.62995-3-git@jeffhostetler.com","subject":"Re: [PATCH v2 2/5] stat_tracking_info: return +1 when branches are not equal","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-12-21T20:48:38Z","receivedAt":"2017-12-21T20:48:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jeff Hostetler wrote:\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1239,7 +1239,7 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,\n>  \t\t*s = show_ref(&atom->u.remote_ref.refname, refname);\n>  \telse if (atom->u.remote_ref.option == RR_TRACK) {\n>  \t\tif (stat_tracking_info(branch, &num_ours,\n> -\t\t\t\t       &num_theirs, NULL)) {\n> +\t\t\t\t       &num_theirs, NULL, ABF_FULL) < 0) {\n\nWhat does ABF stand for?  It made me think of airport codes.\n\nWould a name like AHEADBEHIND_FULL work?\n\n[...]\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -1977,16 +1977,22 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)\n>  }\n>  \n>  /*\n> - * Compare a branch with its upstream, and save their differences (number\n> - * of commits) in *num_ours and *num_theirs. The name of the upstream branch\n> - * (or NULL if no upstream is defined) is returned via *upstream_name, if it\n> - * is not itself NULL.\n> + * Compare a branch with its upstream and report on their differences.\n> + * If abf is ABF_FULL, save their differences (number of commits) in\n> + * *num_ours and *num_theirs.\n> + * If abf is ABF_QUICK, skip the (possibly expensive) ahead/behind\n\nPlease format these comments as paragraphs, with a consistent\nline-width and a \"blank\" (space-star-newline) line between paragraphs.\nThat makes them much easier to read.\n\n[...]\n> @@ -2019,6 +2025,8 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,\n>  \t\t*num_theirs = *num_ours = 0;\n>  \t\treturn 0;\n>  \t}\n> +\tif (abf == ABF_QUICK)\n> +\t\treturn 1;\n\nnit: I think this is missing a blank line before the 'if'.\n\nThanks and hope that helps,\nJonathan\n"},{"id":"335152","messageId":"20171221205749.GC58971@aiede.mtv.corp.google.com","threadId":"47478","inReplyTo":"20171221190909.62995-4-git@jeffhostetler.com","subject":"Re: [PATCH v2 3/5] status: add --[no-]ahead-behind to porcelain V2 output","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2017-12-21T20:57:49Z","receivedAt":"2017-12-21T20:57:58Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nJeff Hostetler wrote:\n\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -141,6 +141,7 @@ static int sequencer_in_use;\n>  static int use_editor = 1, include_status = 1;\n>  static int show_ignored_in_status, have_option_m;\n>  static struct strbuf message = STRBUF_INIT;\n> +static int ahead_behind_opt = -1;\n\nnit: is there a logical place amid these constants to put the new option\ninstead of chronological order to make it easier to read through later?\nThat also has the side-benefit of making the new option less likely to\ncollidate with other patches that add a new option to commit.\n\nThat collection of options seems to be mostly about how the commit\nmessage is generated.  Maybe this one could go after status_format:\n\n\tstatic enum wt_status_format status_format = ...;\n\tstatic int ahead_behind;\n\nEven better if it can be made into a local in cmd_status.\n\n[...]\n> @@ -1369,6 +1370,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n>  \t\t  N_(\"ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)\"),\n>  \t\t  PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n>  \t\tOPT_COLUMN(0, \"column\", &s.colopts, N_(\"list untracked files in columns\")),\n> +\t\tOPT_BOOL(0, \"ahead-behind\", &ahead_behind_opt,\n> +\t\t\t N_(\"compute branch ahead/behind values\")),\n>  \t\tOPT_END(),\n\nSimilar question: is there a natural place in \"git status -h\" to show\nthe new option instead of chronological order?\n\nWhat does the value of the ahead_behind variable represent?  -1 means\nunset so that we use config?  A comment might help.\n\n[...]\n> @@ -1389,6 +1392,21 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n>  \t\t       PATHSPEC_PREFER_FULL,\n>  \t\t       prefix, argv);\n>  \n> +\t/*\n> +\t * Porcelain formats only look at the --[no-]ahead-behind command\n> +\t * line argument and DO NOT look at the config setting.  Non-porcelain\n> +\t * formats use both.\n> +\t */\n\nnit: No need to shout: s/DO NOT/do not/\n\n> +\tif (status_format == STATUS_FORMAT_PORCELAIN ||\n> +\t    status_format == STATUS_FORMAT_PORCELAIN_V2) {\n> +\t\tif (ahead_behind_opt < 0)\n> +\t\t\tahead_behind_opt = ABF_FULL;\n> +\t} else {\n> +\t\tif (ahead_behind_opt < 0)\n> +\t\t\tahead_behind_opt = core_ahead_behind;\n> +\t}\n\nCan be more concise, to save the reader some time if they don't care\nabout the defaulting behavior:\n\n\tif (ahead_behind_opt == -1) {\n\t\tif (status_format == ...)\n\t\t\tahead_behind_opt = ...;\n\t\telse\n\t\t\tahead_behind_opt = ...;\n\t\t}\n\t}\n\n> +\ts.ab_flags = ((ahead_behind_opt) ? ABF_FULL : ABF_QUICK);\n\nnit: both parens here are unnecessary and don't make the code clearer\n\n[...]\n> --- a/t/t7064-wtstatus-pv2.sh\n> +++ b/t/t7064-wtstatus-pv2.sh\n> @@ -390,6 +390,66 @@ test_expect_success 'verify upstream fields in branch header' '\n>  \t)\n>  '\n>  \n> +test_expect_success 'verify --no-ahead-behind generates branch.qab' '\n> +\tgit checkout master &&\n> +\ttest_when_finished \"rm -rf sub_repo\" &&\n> +\tgit clone . sub_repo &&\n> +\t(\n> +\t\t## Confirm local master tracks remote master.\n> +\t\tcd sub_repo &&\n> +\t\tHUF=$(git rev-parse HEAD) &&\n> +\n> +\t\tcat >expect <<-EOF &&\n[...]\n\nThis looks like a collection of multiple tests.  Is there a\nstraightforward way to split them into multiple independent\ntest_expect_successes?\n\nThat way, it's easier to tell which failed if there is a regression\nlater and to run only one of them (using GIT_SKIP_TESTS) when\ndebugging such a failure.\n\nThanks,\nJonathan\n"},{"id":"335179","messageId":"xmqq3742tyho.fsf@gitster.mtv.corp.google.com","threadId":"47478","inReplyTo":"20171221204356.GA58971@aiede.mtv.corp.google.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-12-22T18:21:23Z","receivedAt":"2017-12-22T18:21:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n>> Created core.aheadbehind config setting and core_ahead_behind\n>> global variable.  This value defaults to true.\n>>\n>> This value will be used in the next few commits as the default value\n>> for the --ahead-behind parameter.\n>>\n>> Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n>> ---\n>>  Documentation/config.txt | 8 ++++++++\n>>  cache.h                  | 1 +\n>>  config.c                 | 5 +++++\n>>  environment.c            | 1 +\n>>  4 files changed, 15 insertions(+)\n>\n> Not a reason to reroll on its own, but this seems out of order: the\n> series is easier to explain and easier to merge down in stages if the\n> patch for --ahead-behind comes first, then the config setting.\n>\n> More generally, new commandline flags tend to be less controversial\n> than new config settings since they cannot affect a script by mistake,\n> and for that reason, they can go earlier in the series.\n>\n> As a bonus, that makes it possible to include tests.  It's probably\n> worth adding a test or two for this new config setting.\n>\n> [...]\n>> diff --git a/Documentation/config.txt b/Documentation/config.txt\n>> index 9593bfa..c78d6be 100644\n>> --- a/Documentation/config.txt\n>> +++ b/Documentation/config.txt\n>> @@ -895,6 +895,14 @@ core.abbrev::\n>>  \tabbreviated object names to stay unique for some time.\n>>  \tThe minimum length is 4.\n>>  \n>> +core.aheadbehind::\n>> +\tIf true, tells commands like status and branch to print ahead and\n>> +\tbehind counts for the branch relative to its upstream branch.\n>> +\tThis computation may be very expensive when there is a great\n>> +\tdistance between the two branches.  If false, these commands\n>> +\tonly print that the two branches refer to different commits.\n>> +\tDefaults to true.\n>\n> This doesn't seem like a particularly core feature to me.  Should it be\n> e.g. status.aheadbehind (even though it also affects \"git branch\") or\n> even something like diff.aheadbehind?  I'm not sure.\n\nFWIW, I do not think it is core at all, either; sorry for not\nanticipating that a wrong name will be picked without a proper\nguidance when I saw the \"not limited to status\" mentioned in the\ndiscussion, but I was sick and offline for a few days, so...\n\n> I also wonder if there's a way to achieve the same benefit without\n> having it be configurable.  E.g. if a branch is way behind, couldn't\n> we terminate the walk early to get the same bounded cost per branch\n> without requiring configuration?\n\nHmm, that is an interesting thought.\n"},{"id":"335258","messageId":"20171224143318.GC23648@sigill.intra.peff.net","threadId":"47478","inReplyTo":"xmqq3742tyho.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-12-24T14:33:18Z","receivedAt":"2017-12-24T14:33:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Dec 22, 2017 at 10:21:23AM -0800, Junio C Hamano wrote:\n\n> >> +core.aheadbehind::\n> >> +\tIf true, tells commands like status and branch to print ahead and\n> >> +\tbehind counts for the branch relative to its upstream branch.\n> >> +\tThis computation may be very expensive when there is a great\n> >> +\tdistance between the two branches.  If false, these commands\n> >> +\tonly print that the two branches refer to different commits.\n> >> +\tDefaults to true.\n> >\n> > This doesn't seem like a particularly core feature to me.  Should it be\n> > e.g. status.aheadbehind (even though it also affects \"git branch\") or\n> > even something like diff.aheadbehind?  I'm not sure.\n> \n> FWIW, I do not think it is core at all, either; sorry for not\n> anticipating that a wrong name will be picked without a proper\n> guidance when I saw the \"not limited to status\" mentioned in the\n> discussion, but I was sick and offline for a few days, so...\n\nI, too, had a funny feeling about calling this \"core\". But I didn't have\na better name, as I'm not sure what other place we have for config\noptions that cross many command boundaries. \"diff\" and \"status\" don't\nseem quite right to me. While you can argue they are subsystems, it\nseems too easy for users to confuse them with the commands of the same\nnames.\n\nMaybe there should be a \"ui.*\" config hierarchy for these kinds of\ncross-command interface options?\n\n> > I also wonder if there's a way to achieve the same benefit without\n> > having it be configurable.  E.g. if a branch is way behind, couldn't\n> > we terminate the walk early to get the same bounded cost per branch\n> > without requiring configuration?\n> \n> Hmm, that is an interesting thought.\n\nYes, it is. Two thoughts:\n\n  - It probably doesn't let us punt on the config naming, because we'd\n    probably still want a knob for \"how much work\".\n\n  - I wondered if we could give a better answer than \"these two are\n    different\" based on a partial walk. But certainly not in the general\n    case. E.g., imagine:\n\n      ... -- master -- A -- B -- ... -- Y -- Z -- origin/master\n\n    If we walk back from origin/master and give up somewhere in the\n    middle, we can't say anything intelligent about the relationship.\n\n-Peff\n"},{"id":"335365","messageId":"xmqq1sjgoyph.fsf@gitster.mtv.corp.google.com","threadId":"47478","inReplyTo":"20171224143318.GC23648@sigill.intra.peff.net","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-12-27T17:41:30Z","receivedAt":"2017-12-27T17:41:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I, too, had a funny feeling about calling this \"core\". But I didn't have\n> a better name, as I'm not sure what other place we have for config\n> options that cross many command boundaries. \"diff\" and \"status\" don't\n> seem quite right to me. While you can argue they are subsystems, it\n> seems too easy for users to confuse them with the commands of the same\n> names.\n>\n> Maybe there should be a \"ui.*\" config hierarchy for these kinds of\n> cross-command interface options?\n\nI had an impression that ui.* was primarily pretty-printing,\ncolouring and things of such nature.  I do not think it is such a\nbad idea to honor a status.frotz variable that affects how (e.g. to\nwhat degree of detailedness) status on frotz are reported in Git\nsubcommands other than 'git status' if they report the same sort of\ninformation on 'frotz' that 'git status' makes.\n\n"},{"id":"335637","messageId":"2a5eb18a-d1b4-da2d-c2c8-5798d8627617@jeffhostetler.com","threadId":"47478","inReplyTo":"20171221204356.GA58971@aiede.mtv.corp.google.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2018-01-02T21:54:35Z","receivedAt":"2018-01-02T21:54:42Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"\n\nOn 12/21/2017 3:43 PM, Jonathan Nieder wrote:\n> Hi,\n> \n> Jeff Hostetler wrote:\n> \n>> Created core.aheadbehind config setting and core_ahead_behind\n>> global variable.  This value defaults to true.\n>>\n>> This value will be used in the next few commits as the default value\n>> for the --ahead-behind parameter.\n>>\n>> Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>\n>> ---\n>>   Documentation/config.txt | 8 ++++++++\n>>   cache.h                  | 1 +\n>>   config.c                 | 5 +++++\n>>   environment.c            | 1 +\n>>   4 files changed, 15 insertions(+)\n> \n> Not a reason to reroll on its own, but this seems out of order: the\n> series is easier to explain and easier to merge down in stages if the\n> patch for --ahead-behind comes first, then the config setting.\n> \n> More generally, new commandline flags tend to be less controversial\n> than new config settings since they cannot affect a script by mistake,\n> and for that reason, they can go earlier in the series.\n> \n> As a bonus, that makes it possible to include tests.  It's probably\n> worth adding a test or two for this new config setting.\n\nI'll look at restacking the commits and make this later in the\nseries.  I have tests in a later commit that uses the config setting,\nbut at this point nothing uses it, so I didn't add any tests for it.\nSo maybe with a restacking, I can split up the tests to go with this\nchange.\n\n> \n> [...]\n>> diff --git a/Documentation/config.txt b/Documentation/config.txt\n>> index 9593bfa..c78d6be 100644\n>> --- a/Documentation/config.txt\n>> +++ b/Documentation/config.txt\n>> @@ -895,6 +895,14 @@ core.abbrev::\n>>   \tabbreviated object names to stay unique for some time.\n>>   \tThe minimum length is 4.\n>>   \n>> +core.aheadbehind::\n>> +\tIf true, tells commands like status and branch to print ahead and\n>> +\tbehind counts for the branch relative to its upstream branch.\n>> +\tThis computation may be very expensive when there is a great\n>> +\tdistance between the two branches.  If false, these commands\n>> +\tonly print that the two branches refer to different commits.\n>> +\tDefaults to true.\n> \n> This doesn't seem like a particularly core feature to me.  Should it be\n> e.g. status.aheadbehind (even though it also affects \"git branch\") or\n> even something like diff.aheadbehind?  I'm not sure.\n\nI wasn't sure where to put it after the earlier conversation in V1.\n\n> I also wonder if there's a way to achieve the same benefit without\n> having it be configurable.  E.g. if a branch is way behind, couldn't\n> we terminate the walk early to get the same bounded cost per branch\n> without requiring configuration?\n\nI created a config setting because we don't want to force users to\ntype \"git status --no-ahead-behind\" on every interactive command to\nget the benefit of it.  I guess we could ask them to alias it, if we\ndon't want a config setting.\n\nAlso, I didn't want to change the time-tested behavior that users see,\nso I didn't want to change the algorithm in any way -- just not call it.\n\n\nWould it make more sense to name this something like \"status.aheadBehindLimit\"\nwhere 0 would mean no limit and match existing behavior and a positive\nnumber be the number of commits we are allowed to search before giving up.\nA value of 1 would match the \"different\" case in the current patch series.\nFor most users, a value of say 1000 would be sufficient most of the time\n(and report at most a 999 a/b value), but keep us from going off into the\nweeds for those ridiculous cases with very old branches.\n\n\nThanks,\nJeff\n\n"},{"id":"335638","messageId":"20180102221717.GD131371@aiede.mtv.corp.google.com","threadId":"47478","inReplyTo":"2a5eb18a-d1b4-da2d-c2c8-5798d8627617@jeffhostetler.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2018-01-02T22:17:17Z","receivedAt":"2018-01-02T22:17:25Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nJeff Hostetler wrote:\n> On 12/21/2017 3:43 PM, Jonathan Nieder wrote:\n\n>> I also wonder if there's a way to achieve the same benefit without\n>> having it be configurable.  E.g. if a branch is way behind, couldn't\n>> we terminate the walk early to get the same bounded cost per branch\n>> without requiring configuration?\n>\n> I created a config setting because we don't want to force users to\n> type \"git status --no-ahead-behind\" on every interactive command to\n> get the benefit of it.  I guess we could ask them to alias it, if we\n> don't want a config setting.\n>\n> Also, I didn't want to change the time-tested behavior that users see,\n> so I didn't want to change the algorithm in any way -- just not call it.\n\nI'm not too worried about people relying on the time-tested behavior\nin this case.  It's a convenience feature for human users --- any\nscripts looking for this information would be likely to use a more\nconvenient command like rev-list.\n\nThe one exception is \"git status --porcelain=v2\".  For that command,\nscripts are likely to expect to be able to parse the \"+<ahead>\n-<behind>\" line.  Alas, guarding it with a config doesn't help such\nscripts --- they still need to be able to cope with the new behavior.\n\ngit-status(1) says:\n\n\tParsers should ignore headers that they don't recognize.\n\nso introducing a new line like \"# branch.matchesupstream (true |\nfalse)\" like you did seems reasonable enough.  I *suspect* it should\nbe okay to omit the \"# branch.ab\" line as long as the script didn't\nexplicitly pass --ahead-behind but that depends on whether any scripts\nin the wild were relying on the \"# branch.ab\" line being present.\n\n> Would it make more sense to name this something like \"status.aheadBehindLimit\"\n> where 0 would mean no limit and match existing behavior and a positive\n> number be the number of commits we are allowed to search before giving up.\n\nSounds good to me.\n\nThanks,\nJonathan\n"},{"id":"335843","messageId":"20180104192604.GA27528@sigill.intra.peff.net","threadId":"47478","inReplyTo":"xmqq1sjgoyph.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-01-04T19:26:04Z","receivedAt":"2018-01-04T19:26:10Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Dec 27, 2017 at 09:41:30AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > I, too, had a funny feeling about calling this \"core\". But I didn't have\n> > a better name, as I'm not sure what other place we have for config\n> > options that cross many command boundaries. \"diff\" and \"status\" don't\n> > seem quite right to me. While you can argue they are subsystems, it\n> > seems too easy for users to confuse them with the commands of the same\n> > names.\n> >\n> > Maybe there should be a \"ui.*\" config hierarchy for these kinds of\n> > cross-command interface options?\n> \n> I had an impression that ui.* was primarily pretty-printing,\n> colouring and things of such nature.\n\nI didn't think we had a \"ui.*\" so far. We have \"color.ui\" and\n\"column.ui\", but I think that's it.\n\nAt any rate, my intent was to consider this a \"ui\" issue, in that we are\ndeciding how the ahead/behind hints should be shown to the user.\n\n> I do not think it is such a\n> bad idea to honor a status.frotz variable that affects how (e.g. to\n> what degree of detailedness) status on frotz are reported in Git\n> subcommands other than 'git status' if they report the same sort of\n> information on 'frotz' that 'git status' makes.\n\nIs ahead/behind uniquely attached to git-status? IOW, could this be called\n\"branch.aheadbehind\" and git-status respects it? It seems like putting\nit in status introduces a weird asymmetry.\n\nI buy the argument more that \"status\" here is not \"this is a git-status\nconfig option\", but \"this config section encompasses various things\nabout the status of a repository reported by many commands\". But then\nit's kind of funny to have many of the existing options there that\nreally are specific to git-status.\n\nIn can be both of those things, of course, but then it becomes less\nclear to the user which config options affect which command.\n\nI dunno. It is probably not _that_ big a deal, and I can live with it\nwherever. But Git has a reputation for having inconsistencies and weird\nasymmetries in its UI, so I like to give some thought to squashing them\npreemptively.\n\n-Peff\n"},{"id":"343672","messageId":"091D90DC-DAA2-4338-AAFA-01CB75807992@gmail.com","threadId":"47478","inReplyTo":"20180104192604.GA27528@sigill.intra.peff.net","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Lars Schneider","fromEmail":"larsxschneider@gmail.com","sentAt":"2018-04-03T09:54:33Z","receivedAt":"2018-04-03T09:54:50Z","isPatch":true,"sender":{"key":"larsxschneider@gmail.com","avatar":"https://avatars.githubusercontent.com/u/477434?v=4"},"body":"\n> On 04 Jan 2018, at 20:26, Jeff King <peff@peff.net> wrote:\n> \n> On Wed, Dec 27, 2017 at 09:41:30AM -0800, Junio C Hamano wrote:\n> \n>> Jeff King <peff@peff.net> writes:\n>> \n>>> I, too, had a funny feeling about calling this \"core\". But I didn't have\n>>> a better name, as I'm not sure what other place we have for config\n>>> options that cross many command boundaries. \"diff\" and \"status\" don't\n>>> seem quite right to me. While you can argue they are subsystems, it\n>>> seems too easy for users to confuse them with the commands of the same\n>>> names.\n>>> \n>>> Maybe there should be a \"ui.*\" config hierarchy for these kinds of\n>>> cross-command interface options?\n>> \n>> I had an impression that ui.* was primarily pretty-printing,\n>> colouring and things of such nature.\n> \n> I didn't think we had a \"ui.*\" so far. We have \"color.ui\" and\n> \"column.ui\", but I think that's it.\n> \n> At any rate, my intent was to consider this a \"ui\" issue, in that we are\n> deciding how the ahead/behind hints should be shown to the user.\n> \n>> I do not think it is such a\n>> bad idea to honor a status.frotz variable that affects how (e.g. to\n>> what degree of detailedness) status on frotz are reported in Git\n>> subcommands other than 'git status' if they report the same sort of\n>> information on 'frotz' that 'git status' makes.\n> \n> Is ahead/behind uniquely attached to git-status? IOW, could this be called\n> \"branch.aheadbehind\" and git-status respects it? It seems like putting\n> it in status introduces a weird asymmetry.\n> \n> I buy the argument more that \"status\" here is not \"this is a git-status\n> config option\", but \"this config section encompasses various things\n> about the status of a repository reported by many commands\". But then\n> it's kind of funny to have many of the existing options there that\n> really are specific to git-status.\n> \n> In can be both of those things, of course, but then it becomes less\n> clear to the user which config options affect which command.\n> \n> I dunno. It is probably not _that_ big a deal, and I can live with it\n> wherever. But Git has a reputation for having inconsistencies and weird\n> asymmetries in its UI, so I like to give some thought to squashing them\n> preemptively.\n\nWhat is the state of this series? I can't find it in git/git nor in \ngit-for-windows/git. I think Stolee mentioned the config in\nhis Git Merge talk [1] and I was about to test it/roll it out :-)\n\n- Lars\n\n\n[1] https://youtu.be/oOMzi983Qmw\n\n"},{"id":"343673","messageId":"87vad8vbid.fsf@evledraar.gmail.com","threadId":"47478","inReplyTo":"091D90DC-DAA2-4338-AAFA-01CB75807992@gmail.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-03T10:18:34Z","receivedAt":"2018-04-03T10:18:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Apr 03 2018, Lars Schneider wrote:\n\n>> On 04 Jan 2018, at 20:26, Jeff King <peff@peff.net> wrote:\n>>\n>> On Wed, Dec 27, 2017 at 09:41:30AM -0800, Junio C Hamano wrote:\n>>\n>>> Jeff King <peff@peff.net> writes:\n>>>\n>>>> I, too, had a funny feeling about calling this \"core\". But I didn't have\n>>>> a better name, as I'm not sure what other place we have for config\n>>>> options that cross many command boundaries. \"diff\" and \"status\" don't\n>>>> seem quite right to me. While you can argue they are subsystems, it\n>>>> seems too easy for users to confuse them with the commands of the same\n>>>> names.\n>>>>\n>>>> Maybe there should be a \"ui.*\" config hierarchy for these kinds of\n>>>> cross-command interface options?\n>>>\n>>> I had an impression that ui.* was primarily pretty-printing,\n>>> colouring and things of such nature.\n>>\n>> I didn't think we had a \"ui.*\" so far. We have \"color.ui\" and\n>> \"column.ui\", but I think that's it.\n>>\n>> At any rate, my intent was to consider this a \"ui\" issue, in that we are\n>> deciding how the ahead/behind hints should be shown to the user.\n>>\n>>> I do not think it is such a\n>>> bad idea to honor a status.frotz variable that affects how (e.g. to\n>>> what degree of detailedness) status on frotz are reported in Git\n>>> subcommands other than 'git status' if they report the same sort of\n>>> information on 'frotz' that 'git status' makes.\n>>\n>> Is ahead/behind uniquely attached to git-status? IOW, could this be called\n>> \"branch.aheadbehind\" and git-status respects it? It seems like putting\n>> it in status introduces a weird asymmetry.\n>>\n>> I buy the argument more that \"status\" here is not \"this is a git-status\n>> config option\", but \"this config section encompasses various things\n>> about the status of a repository reported by many commands\". But then\n>> it's kind of funny to have many of the existing options there that\n>> really are specific to git-status.\n>>\n>> In can be both of those things, of course, but then it becomes less\n>> clear to the user which config options affect which command.\n>>\n>> I dunno. It is probably not _that_ big a deal, and I can live with it\n>> wherever. But Git has a reputation for having inconsistencies and weird\n>> asymmetries in its UI, so I like to give some thought to squashing them\n>> preemptively.\n>\n> What is the state of this series? I can't find it in git/git nor in\n> git-for-windows/git. I think Stolee mentioned the config in\n> his Git Merge talk [1] and I was about to test it/roll it out :-)\n\nIt's in the gvfs branch of git@github.com:Microsoft/git.git, i.e. it's\nnot in Git for Windows, but used in Microsoft's own in-house version\nused for Windows.git.\n\nI may be misunderstanding this feature, but my impression was that it\nwas a kludge as a workaround until the commit graph code landed, because\nonce we have that then surely we can just cheaply report the actual (or\napproximate?) number in the common case, but of course it may still be\nslow if your commit graph file is out of date.\n"},{"id":"343676","messageId":"d63b54e9-5ec6-f523-d882-756ac38b882b@gmail.com","threadId":"47478","inReplyTo":"87vad8vbid.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-04-03T11:39:20Z","receivedAt":"2018-04-03T11:39:31Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/3/2018 6:18 AM, Ævar Arnfjörð Bjarmason wrote:\n> On Tue, Apr 03 2018, Lars Schneider wrote:\n>> What is the state of this series? I can't find it in git/git nor in\n>> git-for-windows/git. I think Stolee mentioned the config in\n>> his Git Merge talk [1] and I was about to test it/roll it out :-)\n> It's in the gvfs branch of git@github.com:Microsoft/git.git, i.e. it's\n> not in Git for Windows, but used in Microsoft's own in-house version\n> used for Windows.git.\n\nThanks for adding me to CC. I mentioned it in my talk because that was \none thing we shipped internally as a \"quick fix\" until we could do the \nright thing.\n\nIf I remember correctly, Jeff abandoned shipping this upstream because \nit did have the feel of a hack and we wanted to see if users used the \nconfig setting or really cared about the output values. We saw fast \nadoption of the feature and even turned the config setting on \nautomatically in the following version of GVFS.\n\n> I may be misunderstanding this feature, but my impression was that it\n> was a kludge as a workaround until the commit graph code landed, because\n> once we have that then surely we can just cheaply report the actual (or\n> approximate?) number in the common case, but of course it may still be\n> slow if your commit graph file is out of date.\n\nYou are correct that the commit-graph file may be out of date, causing \nslower performance. Even worse: the current graph patch only provides a \nconstant-multiple speedup (still walking the same number of commits, but \neach commit is parsed much faster).\n\nSpeaking of our GVFS-specific fork [0], the 'gvfs' branch was updated \njust yesterday with a couple of changes that I am prepping for \nsubmission upstream:\n\n* Lazy-load trees when parsing commits from commit-graph [1]\n* Compute and consume generation numbers [2]\n\nEach of these will speed up this ahead/behind calculation in different \nways. [1] makes the cost of loading each commit a bit faster, saving up \nto 20% overall. [2] uses generation numbers in paint_down_to_common() to \nmake the while() condition O(1) instead of O(Q) where Q is the size of \nthe priority queue. The Windows repo is particularly \"wide\" with many \nparallel branches being merged in complicated ways, so the queue becomes \nquite large. This use of generation numbers saves about 4% on some \nahead/behind calculations. This speedup is modest, but the existing code \nalready made good use of limiting the commit walk to be mostly the \n\"important\" commits.\n\nThe real benefit of generation numbers will manifest in a way to make \n--topo-order much faster when rendering a small number of commits.\n\nThe generation numbers _could_ be used to approximate the ahead/behind \ncalculation in the following way: When comparing A and B, and gen(A) < \ngen(B), then A is at least (gen(B) - gen(A)) behind. That's the only \ninformation that can be gathered directly from those values, but may be \nenough to short circuit an exact count.\n\nTo truly accelerate these ahead/behind calculations to be sub-linear* in \nthe ahead/behind counts, we would need a bitmap-based approach. The \nobject-reachability bitmap is a non-starter for client machines in the \nWindows repo, but perhaps a commit-reachability bitmap could be \ninteresting. Performing set operations on the bitmaps could more quickly \nanswer these questions. Just thinking about it makes me want to go down \na deep rabbit hole, investigating ways to compute, store, and use these \nbitmaps. However: let's wait and see how necessary it is as the \ncommit-graph feature stabilizes. (*These bitmap approaches are not \nguaranteed to be sub-linear, because it may include iterating through a \nlist of O(N) bits, but good run-length encodings will likely make the \ncount operation very fast, even with a set-difference operation included.)\n\nThere are too many fun things to work on, not enough time!\n\nThanks,\n-Stolee\n\n[0] https://github.com/microsoft/git\n     Fork of GitForWindows that ships to Windows developers\n\n[1] \nhttps://github.com/Microsoft/git/commit/29114bf86f591f5c87075f779a1faa2d0f17b92f\n     Lazy-load trees when parsing commits from commit-graph \n(accidentally squashed to one commit)\n\n[2] \nhttps://github.com/microsoft/git/compare/879b7d3b1bddea2587b28cdd656c9c655018683a...a0731ca93a35fd042560c4b30e8e0edbdfa4bf9f\n     Compute and consume generation numbers\n"},{"id":"343693","messageId":"36e3a9c3-f7e2-4100-1bfc-647b809a09d0@jeffhostetler.com","threadId":"47478","inReplyTo":"d63b54e9-5ec6-f523-d882-756ac38b882b@gmail.com","subject":"Re: [PATCH v2 1/5] core.aheadbehind: add new config setting","fromName":"Jeff Hostetler","fromEmail":"git@jeffhostetler.com","sentAt":"2018-04-03T13:47:26Z","receivedAt":"2018-04-03T13:47:32Z","isPatch":true,"sender":{"key":"git@jeffhostetler.com","avatar":null},"body":"\n\nOn 4/3/2018 7:39 AM, Derrick Stolee wrote:\n> On 4/3/2018 6:18 AM, Ævar Arnfjörð Bjarmason wrote:\n>> On Tue, Apr 03 2018, Lars Schneider wrote:\n>>> What is the state of this series? I can't find it in git/git nor in\n>>> git-for-windows/git. I think Stolee mentioned the config in\n>>> his Git Merge talk [1] and I was about to test it/roll it out :-)\n>> It's in the gvfs branch of git@github.com:Microsoft/git.git, i.e. it's\n>> not in Git for Windows, but used in Microsoft's own in-house version\n>> used for Windows.git.\n> \n> Thanks for adding me to CC. I mentioned it in my talk because that was one thing we shipped internally as a \"quick fix\" until we could do the right thing.\n> \n> If I remember correctly, Jeff abandoned shipping this upstream because it did have the feel of a hack and we wanted to see if users used the config setting or really cared about the output values. We saw fast adoption of the feature and even turned the config setting on automatically in the following version of GVFS.\n> \n>> I may be misunderstanding this feature, but my impression was that it\n>> was a kludge as a workaround until the commit graph code landed, because\n>> once we have that then surely we can just cheaply report the actual (or\n>> approximate?) number in the common case, but of course it may still be\n>> slow if your commit graph file is out of date.\n\nRight, the only thing in master are the changes to take the new\ncommand line option and to alter the output of status.  We did not\nreach consensus on the need for the config setting and/or whether\nit should be in \"core.\" or \"status.\" or another namespace and/or\nhow it should work.\n\nAnd yes, it was also seen as a hack (just turn it off) until the\nclient-side commit graph was ready (at least for interactive use).\nBecause there are callers that don't need the answer (regardless\nof whether it is cheap to compute) and so the explicit command line\narg limitation is sufficient for them.\n\n\nThis part is in upstream master:\n     commit 4094e47fd2c49fcdbd0152d20ed4d610d72680d7\n     Merge: c710d182ea f39a757dd9\n     Author: Junio C Hamano <gitster@pobox.com>\n     Date:   Thu Mar 8 12:36:24 2018 -0800\n     \n         Merge branch 'jh/status-no-ahead-behind'\n\n\nThese parts are in the 'gvfs' branch in the git@github.com:Microsoft/git.git repo:\n\n     commit 039f65946968fa654a9c3bca27a4f4e93c1c9381\n     Author: Jeff Hostetler <jeffhost@microsoft.com>\n     Date:   Wed Jan 10 13:50:24 2018 -0500\n     \n         status: add warning when a/b calculation takes too long for long/normal format\n\n     commit 0d6756f06d0ad6f1fdc8dba0ead7911e411c9704\n     Author: Jeff Hostetler <jeffhost@microsoft.com>\n     Date:   Mon Feb 5 09:44:04 2018 -0500\n     \n         status: ignore status.aheadbehind in porcelain formats\n\n         Teach porcelain V[12] formats to ignore the status.aheadbehind\n         config setting. They only respect the --[no-]ahead-behind\n         command line argument.  This is for backwards compatibility\n         with existing scripts.\n\n     commit 0dd122d6cd43106a5928587d768a7381cfe9e7a3\n     Author: Jeff Hostetler <jeffhost@microsoft.com>\n     Date:   Tue Jan 9 14:16:07 2018 -0500\n     \n         status: add status.aheadbehind setting\n     \n         Add \"status.aheadbehind\" config setting to change the default\n         behavior of ALL git status formats.\n\nHope this helps,\nJeff\n\n\n"}]}