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
This commit is contained in:
commit
2e6e3e82ee
@ -423,19 +423,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
|
|||||||
char *ref = NULL;
|
char *ref = NULL;
|
||||||
struct branch *branch = branch_get(branch_name);
|
struct branch *branch = branch_get(branch_name);
|
||||||
struct strbuf fancy = STRBUF_INIT;
|
struct strbuf fancy = STRBUF_INIT;
|
||||||
|
int upstream_is_gone = 0;
|
||||||
|
|
||||||
if (!stat_tracking_info(branch, &ours, &theirs)) {
|
switch (stat_tracking_info(branch, &ours, &theirs)) {
|
||||||
if (branch && branch->merge && branch->merge[0]->dst &&
|
case 0:
|
||||||
show_upstream_ref) {
|
/* no base */
|
||||||
ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
|
|
||||||
if (want_color(branch_use_color))
|
|
||||||
strbuf_addf(stat, "[%s%s%s] ",
|
|
||||||
branch_get_color(BRANCH_COLOR_UPSTREAM),
|
|
||||||
ref, branch_get_color(BRANCH_COLOR_RESET));
|
|
||||||
else
|
|
||||||
strbuf_addf(stat, "[%s] ", ref);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
|
case -1:
|
||||||
|
/* with "gone" base */
|
||||||
|
upstream_is_gone = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* with base */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_upstream_ref) {
|
if (show_upstream_ref) {
|
||||||
@ -448,19 +448,25 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
|
|||||||
strbuf_addstr(&fancy, ref);
|
strbuf_addstr(&fancy, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ours) {
|
if (upstream_is_gone) {
|
||||||
if (ref)
|
if (show_upstream_ref)
|
||||||
|
strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
|
||||||
|
} else if (!ours && !theirs) {
|
||||||
|
if (show_upstream_ref)
|
||||||
|
strbuf_addf(stat, _("[%s]"), fancy.buf);
|
||||||
|
} else if (!ours) {
|
||||||
|
if (show_upstream_ref)
|
||||||
strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
|
strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
|
||||||
else
|
else
|
||||||
strbuf_addf(stat, _("[behind %d]"), theirs);
|
strbuf_addf(stat, _("[behind %d]"), theirs);
|
||||||
|
|
||||||
} else if (!theirs) {
|
} else if (!theirs) {
|
||||||
if (ref)
|
if (show_upstream_ref)
|
||||||
strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
|
strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
|
||||||
else
|
else
|
||||||
strbuf_addf(stat, _("[ahead %d]"), ours);
|
strbuf_addf(stat, _("[ahead %d]"), ours);
|
||||||
} else {
|
} else {
|
||||||
if (ref)
|
if (show_upstream_ref)
|
||||||
strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
|
strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
|
||||||
fancy.buf, ours, theirs);
|
fancy.buf, ours, theirs);
|
||||||
else
|
else
|
||||||
|
72
remote.c
72
remote.c
@ -1729,7 +1729,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return true if there is anything to report, otherwise false.
|
* Compare a branch with its upstream, and save their differences (number
|
||||||
|
* of commits) in *num_ours and *num_theirs.
|
||||||
|
*
|
||||||
|
* Return 0 if branch has no upstream (no base), -1 if upstream is missing
|
||||||
|
* (with "gone" base), otherwise 1 (with base).
|
||||||
*/
|
*/
|
||||||
int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
|
int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
|
||||||
{
|
{
|
||||||
@ -1740,34 +1744,30 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
|
|||||||
const char *rev_argv[10], *base;
|
const char *rev_argv[10], *base;
|
||||||
int rev_argc;
|
int rev_argc;
|
||||||
|
|
||||||
/*
|
/* Cannot stat unless we are marked to build on top of somebody else. */
|
||||||
* Nothing to report unless we are marked to build on top of
|
|
||||||
* somebody else.
|
|
||||||
*/
|
|
||||||
if (!branch ||
|
if (!branch ||
|
||||||
!branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
|
!branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/* Cannot stat if what we used to build on no longer exists */
|
||||||
* If what we used to build on no longer exists, there is
|
|
||||||
* nothing to report.
|
|
||||||
*/
|
|
||||||
base = branch->merge[0]->dst;
|
base = branch->merge[0]->dst;
|
||||||
if (read_ref(base, sha1))
|
if (read_ref(base, sha1))
|
||||||
return 0;
|
return -1;
|
||||||
theirs = lookup_commit_reference(sha1);
|
theirs = lookup_commit_reference(sha1);
|
||||||
if (!theirs)
|
if (!theirs)
|
||||||
return 0;
|
return -1;
|
||||||
|
|
||||||
if (read_ref(branch->refname, sha1))
|
if (read_ref(branch->refname, sha1))
|
||||||
return 0;
|
return -1;
|
||||||
ours = lookup_commit_reference(sha1);
|
ours = lookup_commit_reference(sha1);
|
||||||
if (!ours)
|
if (!ours)
|
||||||
return 0;
|
return -1;
|
||||||
|
|
||||||
/* are we the same? */
|
/* are we the same? */
|
||||||
if (theirs == ours)
|
if (theirs == ours) {
|
||||||
return 0;
|
*num_theirs = *num_ours = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Run "rev-list --left-right ours...theirs" internally... */
|
/* Run "rev-list --left-right ours...theirs" internally... */
|
||||||
rev_argc = 0;
|
rev_argc = 0;
|
||||||
@ -1809,31 +1809,53 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
|
|||||||
*/
|
*/
|
||||||
int format_tracking_info(struct branch *branch, struct strbuf *sb)
|
int format_tracking_info(struct branch *branch, struct strbuf *sb)
|
||||||
{
|
{
|
||||||
int num_ours, num_theirs;
|
int ours, theirs;
|
||||||
const char *base;
|
const char *base;
|
||||||
|
int upstream_is_gone = 0;
|
||||||
|
|
||||||
if (!stat_tracking_info(branch, &num_ours, &num_theirs))
|
switch (stat_tracking_info(branch, &ours, &theirs)) {
|
||||||
|
case 0:
|
||||||
|
/* no base */
|
||||||
return 0;
|
return 0;
|
||||||
|
case -1:
|
||||||
|
/* with "gone" base */
|
||||||
|
upstream_is_gone = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* with base */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
base = branch->merge[0]->dst;
|
base = branch->merge[0]->dst;
|
||||||
base = shorten_unambiguous_ref(base, 0);
|
base = shorten_unambiguous_ref(base, 0);
|
||||||
if (!num_theirs) {
|
if (upstream_is_gone) {
|
||||||
|
strbuf_addf(sb,
|
||||||
|
_("Your branch is based on '%s', but the upstream is gone.\n"),
|
||||||
|
base);
|
||||||
|
if (advice_status_hints)
|
||||||
|
strbuf_addf(sb,
|
||||||
|
_(" (use \"git branch --unset-upstream\" to fixup)\n"));
|
||||||
|
} else if (!ours && !theirs) {
|
||||||
|
strbuf_addf(sb,
|
||||||
|
_("Your branch is up-to-date with '%s'.\n"),
|
||||||
|
base);
|
||||||
|
} else if (!theirs) {
|
||||||
strbuf_addf(sb,
|
strbuf_addf(sb,
|
||||||
Q_("Your branch is ahead of '%s' by %d commit.\n",
|
Q_("Your branch is ahead of '%s' by %d commit.\n",
|
||||||
"Your branch is ahead of '%s' by %d commits.\n",
|
"Your branch is ahead of '%s' by %d commits.\n",
|
||||||
num_ours),
|
ours),
|
||||||
base, num_ours);
|
base, ours);
|
||||||
if (advice_status_hints)
|
if (advice_status_hints)
|
||||||
strbuf_addf(sb,
|
strbuf_addf(sb,
|
||||||
_(" (use \"git push\" to publish your local commits)\n"));
|
_(" (use \"git push\" to publish your local commits)\n"));
|
||||||
} else if (!num_ours) {
|
} else if (!ours) {
|
||||||
strbuf_addf(sb,
|
strbuf_addf(sb,
|
||||||
Q_("Your branch is behind '%s' by %d commit, "
|
Q_("Your branch is behind '%s' by %d commit, "
|
||||||
"and can be fast-forwarded.\n",
|
"and can be fast-forwarded.\n",
|
||||||
"Your branch is behind '%s' by %d commits, "
|
"Your branch is behind '%s' by %d commits, "
|
||||||
"and can be fast-forwarded.\n",
|
"and can be fast-forwarded.\n",
|
||||||
num_theirs),
|
theirs),
|
||||||
base, num_theirs);
|
base, theirs);
|
||||||
if (advice_status_hints)
|
if (advice_status_hints)
|
||||||
strbuf_addf(sb,
|
strbuf_addf(sb,
|
||||||
_(" (use \"git pull\" to update your local branch)\n"));
|
_(" (use \"git pull\" to update your local branch)\n"));
|
||||||
@ -1845,8 +1867,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
|
|||||||
"Your branch and '%s' have diverged,\n"
|
"Your branch and '%s' have diverged,\n"
|
||||||
"and have %d and %d different commits each, "
|
"and have %d and %d different commits each, "
|
||||||
"respectively.\n",
|
"respectively.\n",
|
||||||
num_theirs),
|
theirs),
|
||||||
base, num_ours, num_theirs);
|
base, ours, theirs);
|
||||||
if (advice_status_hints)
|
if (advice_status_hints)
|
||||||
strbuf_addf(sb,
|
strbuf_addf(sb,
|
||||||
_(" (use \"git pull\" to merge the remote branch into yours)\n"));
|
_(" (use \"git pull\" to merge the remote branch into yours)\n"));
|
||||||
|
@ -28,10 +28,15 @@ test_expect_success setup '
|
|||||||
git reset --hard HEAD^ &&
|
git reset --hard HEAD^ &&
|
||||||
git checkout -b b4 origin &&
|
git checkout -b b4 origin &&
|
||||||
advance e &&
|
advance e &&
|
||||||
advance f
|
advance f &&
|
||||||
|
git checkout -b brokenbase origin &&
|
||||||
|
git checkout -b b5 --track brokenbase &&
|
||||||
|
advance g &&
|
||||||
|
git branch -d brokenbase &&
|
||||||
|
git checkout -b b6 origin
|
||||||
) &&
|
) &&
|
||||||
git checkout -b follower --track master &&
|
git checkout -b follower --track master &&
|
||||||
advance g
|
advance h
|
||||||
'
|
'
|
||||||
|
|
||||||
script='s/^..\(b.\)[ 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
|
script='s/^..\(b.\)[ 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
|
||||||
@ -56,6 +61,8 @@ b1 origin/master: ahead 1, behind 1
|
|||||||
b2 origin/master: ahead 1, behind 1
|
b2 origin/master: ahead 1, behind 1
|
||||||
b3 origin/master: behind 1
|
b3 origin/master: behind 1
|
||||||
b4 origin/master: ahead 2
|
b4 origin/master: ahead 2
|
||||||
|
b5 brokenbase: gone
|
||||||
|
b6 origin/master
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_expect_success 'branch -vv' '
|
test_expect_success 'branch -vv' '
|
||||||
@ -67,7 +74,7 @@ test_expect_success 'branch -vv' '
|
|||||||
test_i18ncmp expect actual
|
test_i18ncmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'checkout' '
|
test_expect_success 'checkout (diverged from upstream)' '
|
||||||
(
|
(
|
||||||
cd test && git checkout b1
|
cd test && git checkout b1
|
||||||
) >actual &&
|
) >actual &&
|
||||||
@ -80,7 +87,22 @@ test_expect_success 'checkout with local tracked branch' '
|
|||||||
test_i18ngrep "is ahead of" actual
|
test_i18ngrep "is ahead of" actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'status' '
|
test_expect_success 'checkout (upstream is gone)' '
|
||||||
|
(
|
||||||
|
cd test &&
|
||||||
|
git checkout b5
|
||||||
|
) >actual &&
|
||||||
|
test_i18ngrep "is based on .*, but the upstream is gone." actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'checkout (up-to-date with upstream)' '
|
||||||
|
(
|
||||||
|
cd test && git checkout b6
|
||||||
|
) >actual &&
|
||||||
|
test_i18ngrep "Your branch is up-to-date with .origin/master" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'status (diverged from upstream)' '
|
||||||
(
|
(
|
||||||
cd test &&
|
cd test &&
|
||||||
git checkout b1 >/dev/null &&
|
git checkout b1 >/dev/null &&
|
||||||
@ -90,6 +112,65 @@ test_expect_success 'status' '
|
|||||||
test_i18ngrep "have 1 and 1 different" actual
|
test_i18ngrep "have 1 and 1 different" actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'status (upstream is gone)' '
|
||||||
|
(
|
||||||
|
cd test &&
|
||||||
|
git checkout b5 >/dev/null &&
|
||||||
|
# reports nothing to commit
|
||||||
|
test_must_fail git commit --dry-run
|
||||||
|
) >actual &&
|
||||||
|
test_i18ngrep "is based on .*, but the upstream is gone." actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'status (up-to-date with upstream)' '
|
||||||
|
(
|
||||||
|
cd test &&
|
||||||
|
git checkout b6 >/dev/null &&
|
||||||
|
# reports nothing to commit
|
||||||
|
test_must_fail git commit --dry-run
|
||||||
|
) >actual &&
|
||||||
|
test_i18ngrep "Your branch is up-to-date with .origin/master" actual
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >expect <<\EOF
|
||||||
|
## b1...origin/master [ahead 1, behind 1]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'status -s -b (diverged from upstream)' '
|
||||||
|
(
|
||||||
|
cd test &&
|
||||||
|
git checkout b1 >/dev/null &&
|
||||||
|
git status -s -b | head -1
|
||||||
|
) >actual &&
|
||||||
|
test_i18ncmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >expect <<\EOF
|
||||||
|
## b5...brokenbase [gone]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'status -s -b (upstream is gone)' '
|
||||||
|
(
|
||||||
|
cd test &&
|
||||||
|
git checkout b5 >/dev/null &&
|
||||||
|
git status -s -b | head -1
|
||||||
|
) >actual &&
|
||||||
|
test_i18ncmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >expect <<\EOF
|
||||||
|
## b6...origin/master
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'status -s -b (up-to-date with upstream)' '
|
||||||
|
(
|
||||||
|
cd test &&
|
||||||
|
git checkout b6 >/dev/null &&
|
||||||
|
git status -s -b | head -1
|
||||||
|
) >actual &&
|
||||||
|
test_i18ncmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'fail to track lightweight tags' '
|
test_expect_success 'fail to track lightweight tags' '
|
||||||
git checkout master &&
|
git checkout master &&
|
||||||
git tag light &&
|
git tag light &&
|
||||||
|
26
wt-status.c
26
wt-status.c
@ -1363,6 +1363,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
|
|||||||
const char *base;
|
const char *base;
|
||||||
const char *branch_name;
|
const char *branch_name;
|
||||||
int num_ours, num_theirs;
|
int num_ours, num_theirs;
|
||||||
|
int upstream_is_gone = 0;
|
||||||
|
|
||||||
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
|
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
|
||||||
|
|
||||||
@ -1380,20 +1381,37 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
|
|||||||
branch = branch_get(s->branch + 11);
|
branch = branch_get(s->branch + 11);
|
||||||
if (s->is_initial)
|
if (s->is_initial)
|
||||||
color_fprintf(s->fp, header_color, _("Initial commit on "));
|
color_fprintf(s->fp, header_color, _("Initial commit on "));
|
||||||
if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
|
|
||||||
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
|
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
|
||||||
|
|
||||||
|
switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
|
||||||
|
case 0:
|
||||||
|
/* no base */
|
||||||
fputc(s->null_termination ? '\0' : '\n', s->fp);
|
fputc(s->null_termination ? '\0' : '\n', s->fp);
|
||||||
return;
|
return;
|
||||||
|
case -1:
|
||||||
|
/* with "gone" base */
|
||||||
|
upstream_is_gone = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* with base */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
base = branch->merge[0]->dst;
|
base = branch->merge[0]->dst;
|
||||||
base = shorten_unambiguous_ref(base, 0);
|
base = shorten_unambiguous_ref(base, 0);
|
||||||
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
|
|
||||||
color_fprintf(s->fp, header_color, "...");
|
color_fprintf(s->fp, header_color, "...");
|
||||||
color_fprintf(s->fp, branch_color_remote, "%s", base);
|
color_fprintf(s->fp, branch_color_remote, "%s", base);
|
||||||
|
|
||||||
|
if (!upstream_is_gone && !num_ours && !num_theirs) {
|
||||||
|
fputc(s->null_termination ? '\0' : '\n', s->fp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
color_fprintf(s->fp, header_color, " [");
|
color_fprintf(s->fp, header_color, " [");
|
||||||
if (!num_ours) {
|
if (upstream_is_gone) {
|
||||||
|
color_fprintf(s->fp, header_color, _("gone"));
|
||||||
|
} else if (!num_ours) {
|
||||||
color_fprintf(s->fp, header_color, _("behind "));
|
color_fprintf(s->fp, header_color, _("behind "));
|
||||||
color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
|
color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
|
||||||
} else if (!num_theirs) {
|
} else if (!num_theirs) {
|
||||||
|
Loading…
Reference in New Issue
Block a user