Skip to content

Commit f2e0873

Browse files
jiangxingitster
authored andcommitted
branch: report invalid tracking branch as gone
Command "git branch -vv" will report tracking branches, but invalid tracking branches are also reported. This is because the function stat_tracking_info() can not distinguish invalid tracking branch from other cases which it would not like to report, such as there is no upstream settings at all, or nothing is changed between one branch and its upstream. Junio suggested missing upstream should be reported [1] like: $ git branch -v -v master e67ac84 initial * topic 3fc0f2a [topicbase: gone] topic $ git status # On branch topic # Your branch is based on 'topicbase', but the upstream is gone. # (use "git branch --unset-upstream" to fixup) ... $ git status -b -s ## topic...topicbase [gone] ... In order to do like that, we need to distinguish these three cases (i.e. no tracking, with configured but no longer valid tracking, and with tracking) in function stat_tracking_info(). So the refactored function stat_tracking_info() has three return values: -1 (with "gone" base), 0 (no base), and 1 (with base). If the caller does not like to report tracking info when nothing changed between the branch and its upstream, simply checks if num_theirs and num_ours are both 0. [1]: http://thread.gmane.org/gmane.comp.version-control.git/231830/focus=232288 Suggested-by: Junio C Hamano <[email protected]> Signed-off-by: Jiang Xin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 425df88 commit f2e0873

File tree

4 files changed

+142
-48
lines changed

4 files changed

+142
-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: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
16951695
}
16961696

16971697
/*
1698-
* Return true if there is anything to report, otherwise false.
1698+
* Compare a branch with its upstream, and save their differences (number
1699+
* of commits) in *num_ours and *num_theirs.
1700+
*
1701+
* Return 0 if branch has no upstream (no base), -1 if upstream is missing
1702+
* (with "gone" base), otherwise 1 (with base).
16991703
*/
17001704
int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
17011705
{
@@ -1706,34 +1710,30 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
17061710
const char *rev_argv[10], *base;
17071711
int rev_argc;
17081712

1709-
/*
1710-
* Nothing to report unless we are marked to build on top of
1711-
* somebody else.
1712-
*/
1713+
/* Cannot stat unless we are marked to build on top of somebody else. */
17131714
if (!branch ||
17141715
!branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
17151716
return 0;
17161717

1717-
/*
1718-
* If what we used to build on no longer exists, there is
1719-
* nothing to report.
1720-
*/
1718+
/* Cannot stat if what we used to build on no longer exists */
17211719
base = branch->merge[0]->dst;
17221720
if (read_ref(base, sha1))
1723-
return 0;
1721+
return -1;
17241722
theirs = lookup_commit_reference(sha1);
17251723
if (!theirs)
1726-
return 0;
1724+
return -1;
17271725

17281726
if (read_ref(branch->refname, sha1))
1729-
return 0;
1727+
return -1;
17301728
ours = lookup_commit_reference(sha1);
17311729
if (!ours)
1732-
return 0;
1730+
return -1;
17331731

17341732
/* are we the same? */
1735-
if (theirs == ours)
1736-
return 0;
1733+
if (theirs == ours) {
1734+
*num_theirs = *num_ours = 0;
1735+
return 1;
1736+
}
17371737

17381738
/* Run "rev-list --left-right ours...theirs" internally... */
17391739
rev_argc = 0;
@@ -1775,31 +1775,52 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
17751775
*/
17761776
int format_tracking_info(struct branch *branch, struct strbuf *sb)
17771777
{
1778-
int num_ours, num_theirs;
1778+
int ours, theirs;
17791779
const char *base;
1780+
int upstream_is_gone = 0;
17801781

1781-
if (!stat_tracking_info(branch, &num_ours, &num_theirs))
1782+
switch (stat_tracking_info(branch, &ours, &theirs)) {
1783+
case 0:
1784+
/* no base */
17821785
return 0;
1786+
case -1:
1787+
/* with "gone" base */
1788+
upstream_is_gone = 1;
1789+
break;
1790+
default:
1791+
/* Nothing to report if neither side has changes. */
1792+
if (!ours && !theirs)
1793+
return 0;
1794+
/* with base */
1795+
break;
1796+
}
17831797

17841798
base = branch->merge[0]->dst;
17851799
base = shorten_unambiguous_ref(base, 0);
1786-
if (!num_theirs) {
1800+
if (upstream_is_gone) {
1801+
strbuf_addf(sb,
1802+
_("Your branch is based on '%s', but the upstream is gone.\n"),
1803+
base);
1804+
if (advice_status_hints)
1805+
strbuf_addf(sb,
1806+
_(" (use \"git branch --unset-upstream\" to fixup)\n"));
1807+
} else if (!theirs) {
17871808
strbuf_addf(sb,
17881809
Q_("Your branch is ahead of '%s' by %d commit.\n",
17891810
"Your branch is ahead of '%s' by %d commits.\n",
1790-
num_ours),
1791-
base, num_ours);
1811+
ours),
1812+
base, ours);
17921813
if (advice_status_hints)
17931814
strbuf_addf(sb,
17941815
_(" (use \"git push\" to publish your local commits)\n"));
1795-
} else if (!num_ours) {
1816+
} else if (!ours) {
17961817
strbuf_addf(sb,
17971818
Q_("Your branch is behind '%s' by %d commit, "
17981819
"and can be fast-forwarded.\n",
17991820
"Your branch is behind '%s' by %d commits, "
18001821
"and can be fast-forwarded.\n",
1801-
num_theirs),
1802-
base, num_theirs);
1822+
theirs),
1823+
base, theirs);
18031824
if (advice_status_hints)
18041825
strbuf_addf(sb,
18051826
_(" (use \"git pull\" to update your local branch)\n"));
@@ -1811,8 +1832,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
18111832
"Your branch and '%s' have diverged,\n"
18121833
"and have %d and %d different commits each, "
18131834
"respectively.\n",
1814-
num_theirs),
1815-
base, num_ours, num_theirs);
1835+
theirs),
1836+
base, ours, theirs);
18161837
if (advice_status_hints)
18171838
strbuf_addf(sb,
18181839
_(" (use \"git pull\" to merge the remote branch into yours)\n"));

t/t6040-tracking-info.sh

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ 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
3236
) &&
3337
git checkout -b follower --track master &&
34-
advance g
38+
advance h
3539
'
3640

3741
script='s/^..\(b.\)[ 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
@@ -56,6 +60,7 @@ b1 origin/master: ahead 1, behind 1
5660
b2 origin/master: ahead 1, behind 1
5761
b3 origin/master: behind 1
5862
b4 origin/master: ahead 2
63+
b5 brokenbase: gone
5964
EOF
6065

6166
test_expect_success 'branch -vv' '
@@ -67,7 +72,7 @@ test_expect_success 'branch -vv' '
6772
test_i18ncmp expect actual
6873
'
6974

70-
test_expect_success 'checkout' '
75+
test_expect_success 'checkout (diverged from upstream)' '
7176
(
7277
cd test && git checkout b1
7378
) >actual &&
@@ -80,7 +85,15 @@ test_expect_success 'checkout with local tracked branch' '
8085
test_i18ngrep "is ahead of" actual
8186
'
8287

83-
test_expect_success 'status' '
88+
test_expect_success 'checkout (upstream is gone)' '
89+
(
90+
cd test &&
91+
git checkout b5
92+
) >actual &&
93+
test_i18ngrep "is based on .*, but the upstream is gone." actual
94+
'
95+
96+
test_expect_success 'status (diverged from upstream)' '
8497
(
8598
cd test &&
8699
git checkout b1 >/dev/null &&
@@ -90,6 +103,42 @@ test_expect_success 'status' '
90103
test_i18ngrep "have 1 and 1 different" actual
91104
'
92105

106+
test_expect_success 'status (upstream is gone)' '
107+
(
108+
cd test &&
109+
git checkout b5 >/dev/null &&
110+
# reports nothing to commit
111+
test_must_fail git commit --dry-run
112+
) >actual &&
113+
test_i18ngrep "is based on .*, but the upstream is gone." actual
114+
'
115+
116+
cat >expect <<\EOF
117+
## b1...origin/master [ahead 1, behind 1]
118+
EOF
119+
120+
test_expect_success 'status -s -b (diverged from upstream)' '
121+
(
122+
cd test &&
123+
git checkout b1 >/dev/null &&
124+
git status -s -b | head -1
125+
) >actual &&
126+
test_i18ncmp expect actual
127+
'
128+
129+
cat >expect <<\EOF
130+
## b5...brokenbase [gone]
131+
EOF
132+
133+
test_expect_success 'status -s -b (upstream is gone)' '
134+
(
135+
cd test &&
136+
git checkout b5 >/dev/null &&
137+
git status -s -b | head -1
138+
) >actual &&
139+
test_i18ncmp expect actual
140+
'
141+
93142
test_expect_success 'fail to track lightweight tags' '
94143
git checkout master &&
95144
git tag light &&

wt-status.c

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

13691370
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
13701371

@@ -1382,20 +1383,37 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
13821383
branch = branch_get(s->branch + 11);
13831384
if (s->is_initial)
13841385
color_fprintf(s->fp, header_color, _("Initial commit on "));
1385-
if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
1386-
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
1386+
1387+
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
1388+
1389+
switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
1390+
case 0:
1391+
/* no base */
13871392
fputc(s->null_termination ? '\0' : '\n', s->fp);
13881393
return;
1394+
case -1:
1395+
/* with "gone" base */
1396+
upstream_is_gone = 1;
1397+
break;
1398+
default:
1399+
/* Stop reporting if neither side has changes. */
1400+
if (!num_ours && !num_theirs) {
1401+
fputc(s->null_termination ? '\0' : '\n', s->fp);
1402+
return;
1403+
}
1404+
/* with base */
1405+
break;
13891406
}
13901407

13911408
base = branch->merge[0]->dst;
13921409
base = shorten_unambiguous_ref(base, 0);
1393-
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
13941410
color_fprintf(s->fp, header_color, "...");
13951411
color_fprintf(s->fp, branch_color_remote, "%s", base);
13961412

13971413
color_fprintf(s->fp, header_color, " [");
1398-
if (!num_ours) {
1414+
if (upstream_is_gone) {
1415+
color_fprintf(s->fp, header_color, _("gone"));
1416+
} else if (!num_ours) {
13991417
color_fprintf(s->fp, header_color, _("behind "));
14001418
color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
14011419
} else if (!num_theirs) {

0 commit comments

Comments
 (0)