status: add --[no-]ahead-behind to status and commit for V2 format.
Teach "git status" and "git commit" to accept "--no-ahead-behind" and "--ahead-behind" arguments to request quick or full ahead/behind reporting. When "--no-ahead-behind" is given, the existing porcelain V2 line "branch.ab +x -y" is replaced with a new "branch.ab +? -?" line. This indicates that the branch and its upstream are or are not equal without the expense of computing the full ahead/behind values. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff Hostetler committed
Jan 9, 2018 at 18:50 UTC
fd9b544a2991ad74d73ad1bc0af4d24f91a6802b
7 files changed
+102
-11
Documentation/git-status.txt
+5
@@ -130,6 +130,11 @@ ignored, then the directory is not shown, but all contents are shown.
130
without options are equivalent to 'always' and 'never'
131
respectively.
132
133
+--ahead-behind::
134
+--no-ahead-behind::
135
+ Display or do not display detailed ahead/behind counts for the
136
+ branch relative to its upstream branch. Defaults to true.
137
+
138
<pathspec>...::
139
See the 'pathspec' entry in linkgit:gitglossary[7].
140
builtin/commit.c
+7
@@ -1151,6 +1151,9 @@ static void finalize_deferred_config(struct wt_status *s)
1151
s->show_branch = status_deferred_config.show_branch;
1152
if (s->show_branch < 0)
1153
s->show_branch = 0;
1154
+
1155
+ if (s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED)
1156
+ s->ahead_behind_flags = AHEAD_BEHIND_FULL;
1157
}
1158
1159
static int parse_and_validate_options(int argc, const char *argv[],
@@ -1365,6 +1368,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
1368
N_("show branch information")),
1369
OPT_BOOL(0, "show-stash", &s.show_stash,
1370
N_("show stash information")),
1371
+ OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
1372
+ N_("compute full ahead/behind values")),
1373
{ OPTION_CALLBACK, 0, "porcelain", &status_format,
1374
N_("version"), N_("machine-readable output"),
1375
PARSE_OPT_OPTARG, opt_parse_porcelain },
@@ -1648,6 +1653,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
1653
OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
1654
STATUS_FORMAT_SHORT),
1655
OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")),
1656
+ OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
1657
+ N_("compute full ahead/behind values")),
1658
OPT_SET_INT(0, "porcelain", &status_format,
1659
N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
1660
OPT_SET_INT(0, "long", &status_format,
remote.c
+2
@@ -2058,6 +2058,8 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs,
2058
return 0;
2059
if (abf == AHEAD_BEHIND_QUICK)
2060
return 1;
2061
+ if (abf != AHEAD_BEHIND_FULL)
2062
+ BUG("stat_tracking_info: invalid abf '%d'", abf);
2063
2064
/* Run "rev-list --left-right ours...theirs" internally... */
2065
argv_array_push(&argv, ""); /* ignored */
remote.h
+3
-2
@@ -259,8 +259,9 @@ enum match_refs_flags {
259
260
/* Flags for --ahead-behind option. */
261
enum ahead_behind_flags {
262
- AHEAD_BEHIND_QUICK = 0, /* just eq/neq reporting */
263
- AHEAD_BEHIND_FULL = 1, /* traditional a/b reporting */
262
+ AHEAD_BEHIND_UNSPECIFIED = -1,
263
+ AHEAD_BEHIND_QUICK = 0, /* just eq/neq reporting */
264
+ AHEAD_BEHIND_FULL = 1, /* traditional a/b reporting */
265
};
266
267
/* Reporting of tracking info */
t/t7064-wtstatus-pv2.sh
+62
@@ -390,6 +390,68 @@ test_expect_success 'verify upstream fields in branch header' '
390
)
391
'
392
393
+test_expect_success 'verify --[no-]ahead-behind with V2 format' '
394
+ git checkout master &&
395
+ test_when_finished "rm -rf sub_repo" &&
396
+ git clone . sub_repo &&
397
+ (
398
+ ## Confirm local master tracks remote master.
399
+ cd sub_repo &&
400
+ HUF=$(git rev-parse HEAD) &&
401
+
402
+ # Confirm --no-ahead-behind reports traditional branch.ab with 0/0 for equal branches.
403
+ cat >expect <<-EOF &&
404
+ # branch.oid $HUF
405
+ # branch.head master
406
+ # branch.upstream origin/master
407
+ # branch.ab +0 -0
408
+ EOF
409
+
410
+ git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
411
+ test_cmp expect actual &&
412
+
413
+ # Confirm --ahead-behind reports traditional branch.ab with 0/0.
414
+ cat >expect <<-EOF &&
415
+ # branch.oid $HUF
416
+ # branch.head master
417
+ # branch.upstream origin/master
418
+ # branch.ab +0 -0
419
+ EOF
420
+
421
+ git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
422
+ test_cmp expect actual &&
423
+
424
+ ## Test non-equal ahead/behind.
425
+ echo xyz >file_xyz &&
426
+ git add file_xyz &&
427
+ git commit -m xyz &&
428
+
429
+ HUF=$(git rev-parse HEAD) &&
430
+
431
+ # Confirm --no-ahead-behind reports branch.ab with ?/? for non-equal branches.
432
+ cat >expect <<-EOF &&
433
+ # branch.oid $HUF
434
+ # branch.head master
435
+ # branch.upstream origin/master
436
+ # branch.ab +? -?
437
+ EOF
438
+
439
+ git status --no-ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
440
+ test_cmp expect actual &&
441
+
442
+ # Confirm --ahead-behind reports traditional branch.ab with 1/0.
443
+ cat >expect <<-EOF &&
444
+ # branch.oid $HUF
445
+ # branch.head master
446
+ # branch.upstream origin/master
447
+ # branch.ab +1 -0
448
+ EOF
449
+
450
+ git status --ahead-behind --porcelain=v2 --branch --untracked-files=all >actual &&
451
+ test_cmp expect actual
452
+ )
453
+'
454
+
455
test_expect_success 'create and add submodule, submodule appears clean (A. S...)' '
456
git checkout master &&
457
git clone . sub_repo &&
wt-status.c
+21
-9
@@ -136,6 +136,7 @@ void wt_status_prepare(struct wt_status *s)
136
s->ignored.strdup_strings = 1;
137
s->show_branch = -1; /* unspecified */
138
s->show_stash = 0;
139
+ s->ahead_behind_flags = AHEAD_BEHIND_UNSPECIFIED;
140
s->display_comment_prefix = 0;
141
}
142
@@ -1883,18 +1884,19 @@ static void wt_porcelain_print(struct wt_status *s)
1884
*
1885
* <upstream> ::= the upstream branch name, when set.
1886
*
1886
- * <ahead> ::= integer ahead value, when upstream set
1887
- * and the commit is present (not gone).
1888
- *
1889
- * <behind> ::= integer behind value, when upstream set
1890
- * and commit is present.
1887
+ * <ahead> ::= integer ahead value or '?'.
1888
*
1889
+ * <behind> ::= integer behind value or '?'.
1890
*
1891
* The end-of-line is defined by the -z flag.
1892
*
1893
* <eol> ::= NUL when -z,
1894
* LF when NOT -z.
1895
*
1896
+ * When an upstream is set and present, the 'branch.ab' line will
1897
+ * be printed with the ahead/behind counts for the branch and the
1898
+ * upstream. When AHEAD_BEHIND_QUICK is requested and the branches
1899
+ * are different, '?' will be substituted for the actual count.
1900
*/
1901
static void wt_porcelain_v2_print_tracking(struct wt_status *s)
1902
{
@@ -1934,15 +1936,25 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)
1936
/* Lookup stats on the upstream tracking branch, if set. */
1937
branch = branch_get(branch_name);
1938
base = NULL;
1937
- ab_info = (stat_tracking_info(branch, &nr_ahead, &nr_behind,
1938
- &base, AHEAD_BEHIND_FULL) >= 0);
1939
+ ab_info = stat_tracking_info(branch, &nr_ahead, &nr_behind,
1940
+ &base, s->ahead_behind_flags);
1941
if (base) {
1942
base = shorten_unambiguous_ref(base, 0);
1943
fprintf(s->fp, "# branch.upstream %s%c", base, eol);
1944
free((char *)base);
1945
1944
- if (ab_info)
1945
- fprintf(s->fp, "# branch.ab +%d -%d%c", nr_ahead, nr_behind, eol);
1946
+ if (ab_info > 0) {
1947
+ /* different */
1948
+ if (nr_ahead || nr_behind)
1949
+ fprintf(s->fp, "# branch.ab +%d -%d%c",
1950
+ nr_ahead, nr_behind, eol);
1951
+ else
1952
+ fprintf(s->fp, "# branch.ab +? -?%c",
1953
+ eol);
1954
+ } else if (!ab_info) {
1955
+ /* same */
1956
+ fprintf(s->fp, "# branch.ab +0 -0%c", eol);
1957
+ }
1958
}
1959
}
1960
wt-status.h
+2
@@ -5,6 +5,7 @@
5
#include "string-list.h"
6
#include "color.h"
7
#include "pathspec.h"
8
+#include "remote.h"
9
10
struct worktree;
11
@@ -86,6 +87,7 @@ struct wt_status {
87
int show_branch;
88
int show_stash;
89
int hints;
90
+ enum ahead_behind_flags ahead_behind_flags;
91
92
enum wt_status_format status_format;
93
unsigned char sha1_commit[GIT_MAX_RAWSZ]; /* when not Initial */