Skip to content

Commit 2e6e3e8

Browse files
committed
Merge branch 'jx/branch-vv-always-compare-with-upstream'
"git branch -v -v" (and "git status") did not distinguish among a branch that does not build on any other branch, a branch that is in sync with the branch it builds on, and a branch that is configured to build on some other branch that no longer exists. * jx/branch-vv-always-compare-with-upstream: status: always show tracking branch even no change branch: report invalid tracking branch as gone
2 parents 238504b + f223459 commit 2e6e3e8

File tree

4 files changed

+175
-48
lines changed

4 files changed

+175
-48
lines changed

builtin/branch.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -423,19 +423,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
423423
char *ref = NULL;
424424
struct branch *branch = branch_get(branch_name);
425425
struct strbuf fancy = STRBUF_INIT;
426+
int upstream_is_gone = 0;
426427

427-
if (!stat_tracking_info(branch, &ours, &theirs)) {
428-
if (branch && branch->merge && branch->merge[0]->dst &&
429-
show_upstream_ref) {
430-
ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
431-
if (want_color(branch_use_color))
432-
strbuf_addf(stat, "[%s%s%s] ",
433-
branch_get_color(BRANCH_COLOR_UPSTREAM),
434-
ref, branch_get_color(BRANCH_COLOR_RESET));
435-
else
436-
strbuf_addf(stat, "[%s] ", ref);
437-
}
428+
switch (stat_tracking_info(branch, &ours, &theirs)) {
429+
case 0:
430+
/* no base */
438431
return;
432+
case -1:
433+
/* with "gone" base */
434+
upstream_is_gone = 1;
435+
break;
436+
default:
437+
/* with base */
438+
break;
439439
}
440440

441441
if (show_upstream_ref) {
@@ -448,19 +448,25 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
448448
strbuf_addstr(&fancy, ref);
449449
}
450450

451-
if (!ours) {
452-
if (ref)
451+
if (upstream_is_gone) {
452+
if (show_upstream_ref)
453+
strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
454+
} else if (!ours && !theirs) {
455+
if (show_upstream_ref)
456+
strbuf_addf(stat, _("[%s]"), fancy.buf);
457+
} else if (!ours) {
458+
if (show_upstream_ref)
453459
strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
454460
else
455461
strbuf_addf(stat, _("[behind %d]"), theirs);
456462

457463
} else if (!theirs) {
458-
if (ref)
464+
if (show_upstream_ref)
459465
strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
460466
else
461467
strbuf_addf(stat, _("[ahead %d]"), ours);
462468
} else {
463-
if (ref)
469+
if (show_upstream_ref)
464470
strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
465471
fancy.buf, ours, theirs);
466472
else

remote.c

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,7 +1729,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
17291729
}
17301730

17311731
/*
1732-
* Return true if there is anything to report, otherwise false.
1732+
* Compare a branch with its upstream, and save their differences (number
1733+
* of commits) in *num_ours and *num_theirs.
1734+
*
1735+
* Return 0 if branch has no upstream (no base), -1 if upstream is missing
1736+
* (with "gone" base), otherwise 1 (with base).
17331737
*/
17341738
int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
17351739
{
@@ -1740,34 +1744,30 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
17401744
const char *rev_argv[10], *base;
17411745
int rev_argc;
17421746

1743-
/*
1744-
* Nothing to report unless we are marked to build on top of
1745-
* somebody else.
1746-
*/
1747+
/* Cannot stat unless we are marked to build on top of somebody else. */
17471748
if (!branch ||
17481749
!branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
17491750
return 0;
17501751

1751-
/*
1752-
* If what we used to build on no longer exists, there is
1753-
* nothing to report.
1754-
*/
1752+
/* Cannot stat if what we used to build on no longer exists */
17551753
base = branch->merge[0]->dst;
17561754
if (read_ref(base, sha1))
1757-
return 0;
1755+
return -1;
17581756
theirs = lookup_commit_reference(sha1);
17591757
if (!theirs)
1760-
return 0;
1758+
return -1;
17611759

17621760
if (read_ref(branch->refname, sha1))
1763-
return 0;
1761+
return -1;
17641762
ours = lookup_commit_reference(sha1);
17651763
if (!ours)
1766-
return 0;
1764+
return -1;
17671765

17681766
/* are we the same? */
1769-
if (theirs == ours)
1770-
return 0;
1767+
if (theirs == ours) {
1768+
*num_theirs = *num_ours = 0;
1769+
return 1;
1770+
}
17711771

17721772
/* Run "rev-list --left-right ours...theirs" internally... */
17731773
rev_argc = 0;
@@ -1809,31 +1809,53 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
18091809
*/
18101810
int format_tracking_info(struct branch *branch, struct strbuf *sb)
18111811
{
1812-
int num_ours, num_theirs;
1812+
int ours, theirs;
18131813
const char *base;
1814+
int upstream_is_gone = 0;
18141815

1815-
if (!stat_tracking_info(branch, &num_ours, &num_theirs))
1816+
switch (stat_tracking_info(branch, &ours, &theirs)) {
1817+
case 0:
1818+
/* no base */
18161819
return 0;
1820+
case -1:
1821+
/* with "gone" base */
1822+
upstream_is_gone = 1;
1823+
break;
1824+
default:
1825+
/* with base */
1826+
break;
1827+
}
18171828

18181829
base = branch->merge[0]->dst;
18191830
base = shorten_unambiguous_ref(base, 0);
1820-
if (!num_theirs) {
1831+
if (upstream_is_gone) {
1832+
strbuf_addf(sb,
1833+
_("Your branch is based on '%s', but the upstream is gone.\n"),
1834+
base);
1835+
if (advice_status_hints)
1836+
strbuf_addf(sb,
1837+
_(" (use \"git branch --unset-upstream\" to fixup)\n"));
1838+
} else if (!ours && !theirs) {
1839+
strbuf_addf(sb,
1840+
_("Your branch is up-to-date with '%s'.\n"),
1841+
base);
1842+
} else if (!theirs) {
18211843
strbuf_addf(sb,
18221844
Q_("Your branch is ahead of '%s' by %d commit.\n",
18231845
"Your branch is ahead of '%s' by %d commits.\n",
1824-
num_ours),
1825-
base, num_ours);
1846+
ours),
1847+
base, ours);
18261848
if (advice_status_hints)
18271849
strbuf_addf(sb,
18281850
_(" (use \"git push\" to publish your local commits)\n"));
1829-
} else if (!num_ours) {
1851+
} else if (!ours) {
18301852
strbuf_addf(sb,
18311853
Q_("Your branch is behind '%s' by %d commit, "
18321854
"and can be fast-forwarded.\n",
18331855
"Your branch is behind '%s' by %d commits, "
18341856
"and can be fast-forwarded.\n",
1835-
num_theirs),
1836-
base, num_theirs);
1857+
theirs),
1858+
base, theirs);
18371859
if (advice_status_hints)
18381860
strbuf_addf(sb,
18391861
_(" (use \"git pull\" to update your local branch)\n"));
@@ -1845,8 +1867,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
18451867
"Your branch and '%s' have diverged,\n"
18461868
"and have %d and %d different commits each, "
18471869
"respectively.\n",
1848-
num_theirs),
1849-
base, num_ours, num_theirs);
1870+
theirs),
1871+
base, ours, theirs);
18501872
if (advice_status_hints)
18511873
strbuf_addf(sb,
18521874
_(" (use \"git pull\" to merge the remote branch into yours)\n"));

t/t6040-tracking-info.sh

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@ test_expect_success setup '
2828
git reset --hard HEAD^ &&
2929
git checkout -b b4 origin &&
3030
advance e &&
31-
advance f
31+
advance f &&
32+
git checkout -b brokenbase origin &&
33+
git checkout -b b5 --track brokenbase &&
34+
advance g &&
35+
git branch -d brokenbase &&
36+
git checkout -b b6 origin
3237
) &&
3338
git checkout -b follower --track master &&
34-
advance g
39+
advance h
3540
'
3641

3742
script='s/^..\(b.\)[ 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
@@ -56,6 +61,8 @@ b1 origin/master: ahead 1, behind 1
5661
b2 origin/master: ahead 1, behind 1
5762
b3 origin/master: behind 1
5863
b4 origin/master: ahead 2
64+
b5 brokenbase: gone
65+
b6 origin/master
5966
EOF
6067

6168
test_expect_success 'branch -vv' '
@@ -67,7 +74,7 @@ test_expect_success 'branch -vv' '
6774
test_i18ncmp expect actual
6875
'
6976

70-
test_expect_success 'checkout' '
77+
test_expect_success 'checkout (diverged from upstream)' '
7178
(
7279
cd test && git checkout b1
7380
) >actual &&
@@ -80,7 +87,22 @@ test_expect_success 'checkout with local tracked branch' '
8087
test_i18ngrep "is ahead of" actual
8188
'
8289

83-
test_expect_success 'status' '
90+
test_expect_success 'checkout (upstream is gone)' '
91+
(
92+
cd test &&
93+
git checkout b5
94+
) >actual &&
95+
test_i18ngrep "is based on .*, but the upstream is gone." actual
96+
'
97+
98+
test_expect_success 'checkout (up-to-date with upstream)' '
99+
(
100+
cd test && git checkout b6
101+
) >actual &&
102+
test_i18ngrep "Your branch is up-to-date with .origin/master" actual
103+
'
104+
105+
test_expect_success 'status (diverged from upstream)' '
84106
(
85107
cd test &&
86108
git checkout b1 >/dev/null &&
@@ -90,6 +112,65 @@ test_expect_success 'status' '
90112
test_i18ngrep "have 1 and 1 different" actual
91113
'
92114

115+
test_expect_success 'status (upstream is gone)' '
116+
(
117+
cd test &&
118+
git checkout b5 >/dev/null &&
119+
# reports nothing to commit
120+
test_must_fail git commit --dry-run
121+
) >actual &&
122+
test_i18ngrep "is based on .*, but the upstream is gone." actual
123+
'
124+
125+
test_expect_success 'status (up-to-date with upstream)' '
126+
(
127+
cd test &&
128+
git checkout b6 >/dev/null &&
129+
# reports nothing to commit
130+
test_must_fail git commit --dry-run
131+
) >actual &&
132+
test_i18ngrep "Your branch is up-to-date with .origin/master" actual
133+
'
134+
135+
cat >expect <<\EOF
136+
## b1...origin/master [ahead 1, behind 1]
137+
EOF
138+
139+
test_expect_success 'status -s -b (diverged from upstream)' '
140+
(
141+
cd test &&
142+
git checkout b1 >/dev/null &&
143+
git status -s -b | head -1
144+
) >actual &&
145+
test_i18ncmp expect actual
146+
'
147+
148+
cat >expect <<\EOF
149+
## b5...brokenbase [gone]
150+
EOF
151+
152+
test_expect_success 'status -s -b (upstream is gone)' '
153+
(
154+
cd test &&
155+
git checkout b5 >/dev/null &&
156+
git status -s -b | head -1
157+
) >actual &&
158+
test_i18ncmp expect actual
159+
'
160+
161+
cat >expect <<\EOF
162+
## b6...origin/master
163+
EOF
164+
165+
test_expect_success 'status -s -b (up-to-date with upstream)' '
166+
(
167+
cd test &&
168+
git checkout b6 >/dev/null &&
169+
git status -s -b | head -1
170+
) >actual &&
171+
test_i18ncmp expect actual
172+
'
173+
93174
test_expect_success 'fail to track lightweight tags' '
94175
git checkout master &&
95176
git tag light &&

wt-status.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
13631363
const char *base;
13641364
const char *branch_name;
13651365
int num_ours, num_theirs;
1366+
int upstream_is_gone = 0;
13661367

13671368
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
13681369

@@ -1380,20 +1381,37 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
13801381
branch = branch_get(s->branch + 11);
13811382
if (s->is_initial)
13821383
color_fprintf(s->fp, header_color, _("Initial commit on "));
1383-
if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
1384-
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
1384+
1385+
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
1386+
1387+
switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
1388+
case 0:
1389+
/* no base */
13851390
fputc(s->null_termination ? '\0' : '\n', s->fp);
13861391
return;
1392+
case -1:
1393+
/* with "gone" base */
1394+
upstream_is_gone = 1;
1395+
break;
1396+
default:
1397+
/* with base */
1398+
break;
13871399
}
13881400

13891401
base = branch->merge[0]->dst;
13901402
base = shorten_unambiguous_ref(base, 0);
1391-
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
13921403
color_fprintf(s->fp, header_color, "...");
13931404
color_fprintf(s->fp, branch_color_remote, "%s", base);
13941405

1406+
if (!upstream_is_gone && !num_ours && !num_theirs) {
1407+
fputc(s->null_termination ? '\0' : '\n', s->fp);
1408+
return;
1409+
}
1410+
13951411
color_fprintf(s->fp, header_color, " [");
1396-
if (!num_ours) {
1412+
if (upstream_is_gone) {
1413+
color_fprintf(s->fp, header_color, _("gone"));
1414+
} else if (!num_ours) {
13971415
color_fprintf(s->fp, header_color, _("behind "));
13981416
color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
13991417
} else if (!num_theirs) {

0 commit comments

Comments
 (0)