git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [RFC] status: show tracking branch even no difference
@ 2013-08-07 15:42 Jiang Xin
  2013-08-07 15:50 ` Matthieu Moy
  0 siblings, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-07 15:42 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List, Jiang Xin

If the current branch has an upstream branch, and there are differences
between the current branch and its upstream, some commands (such as
"git status", "git status -bs", and "git checkout") will report their
relationship. E.g.

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    #   (use "git push" to publish your local commits)
    #
    ...

    $ git status -bs
    ## master...origin/master [ahead 1]
    ...

    $ git checkout master
    Already on 'master'
    Your branch is ahead of 'origin/master' by 1 commit.
      (use "git push" to publish your local commits)

But if there is no difference between the current branch and its
upstream, the relationship will not be reported, and it's hard to
tell whether the current branch has a tracking branch or not. And
what's worse, when the 'push.default' config variable is set to
`matching`, it's hard to tell whether current branch is pushed out
or not [1].

With this patch, "git status" will report relationship between current
branch and its upstream counterpart even if there is no difference.

    $ git status
    # On branch master
    # Your branch is identical to its tracking branch: 'origin/master'.
    #
    ...

    $ git status -bs
    ## master...origin/master
    ...

    $ git checkout master
    Already on 'master'
    Your branch is identical to its tracking branch: 'origin/master'.

[1]: http://thread.gmane.org/gmane.comp.version-control.git/198703

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 remote.c    | 22 ++++++++++++++++------
 wt-status.c | 13 ++++++++++---
 2 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/remote.c b/remote.c
index 2433467..8d6f278 100644
--- a/remote.c
+++ b/remote.c
@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
+	/* Set both num_theirs and num_ours as undetermined. */
+	*num_theirs = -1;
+	*num_ours = -1;
+
 	/*
 	 * Nothing to report unless we are marked to build on top of
 	 * somebody else.
@@ -1758,14 +1762,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	theirs = lookup_commit_reference(sha1);
 	if (!theirs)
 		return 0;
+	*num_theirs = 0;
 
 	if (read_ref(branch->refname, sha1))
 		return 0;
 	ours = lookup_commit_reference(sha1);
 	if (!ours)
 		return 0;
+	*num_ours = 0;
 
-	/* are we the same? */
+	/* are we the same? both num_theirs and num_ours are set to 0. */
 	if (theirs == ours)
 		return 0;
 
@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	prepare_revision_walk(&revs);
 
 	/* ... and count the commits on each side. */
-	*num_ours = 0;
-	*num_theirs = 0;
 	while (1) {
 		struct commit *c = get_revision(&revs);
 		if (!c)
@@ -1812,12 +1816,18 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 	int num_ours, num_theirs;
 	const char *base;
 
-	if (!stat_tracking_info(branch, &num_ours, &num_theirs))
-		return 0;
+	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
+		if (num_ours || num_theirs)
+			return 0;
+	}
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!num_theirs) {
+	if (!num_ours && !num_theirs) {
+		strbuf_addf(sb,
+			_("Your branch is identical to its tracking branch: '%s'.\n"),
+			base);
+	} else if (!num_theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
diff --git a/wt-status.c b/wt-status.c
index ff4b324..56f3c19 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1381,9 +1381,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	if (s->is_initial)
 		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);
-		fputc(s->null_termination ? '\0' : '\n', s->fp);
-		return;
+		if (num_ours || num_theirs) {
+			color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+			fputc(s->null_termination ? '\0' : '\n', s->fp);
+			return;
+		}
 	}
 
 	base = branch->merge[0]->dst;
@@ -1392,6 +1394,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, header_color, "...");
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
+	if (!num_ours && !num_theirs) {
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+
 	color_fprintf(s->fp, header_color, " [");
 	if (!num_ours) {
 		color_fprintf(s->fp, header_color, _("behind "));
-- 
1.8.4.rc1.429.g46fb194

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [RFC] status: show tracking branch even no difference
  2013-08-07 15:42 [RFC] status: show tracking branch even no difference Jiang Xin
@ 2013-08-07 15:50 ` Matthieu Moy
  2013-08-07 16:03   ` Jiang Xin
  2013-08-08  5:40   ` [PATCH v2] status: always show tracking branch even no change Jiang Xin
  0 siblings, 2 replies; 36+ messages in thread
From: Matthieu Moy @ 2013-08-07 15:50 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Junio C Hamano, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> With this patch, "git status" will report relationship between current
> branch and its upstream counterpart even if there is no difference.
>
>     $ git status
>     # On branch master
>     # Your branch is identical to its tracking branch: 'origin/master'.

Why not, but we try to say "remote-tracking branch" instead of just
"tracking". Adding "remote-" in your wording may make the line a bit
long, but it may be sufficient to say

# Your branch is identical to 'origin/master'

That's consistant with other messages like

# Your branch is ahead of '%s' by %d commits

(And this would deserve a test)

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC] status: show tracking branch even no difference
  2013-08-07 15:50 ` Matthieu Moy
@ 2013-08-07 16:03   ` Jiang Xin
  2013-08-08  5:40   ` [PATCH v2] status: always show tracking branch even no change Jiang Xin
  1 sibling, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-07 16:03 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Junio C Hamano, Git List

2013/8/7 Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>:
> Jiang Xin <worldhello.net@gmail.com> writes:
>
>> With this patch, "git status" will report relationship between current
>> branch and its upstream counterpart even if there is no difference.
>>
>>     $ git status
>>     # On branch master
>>     # Your branch is identical to its tracking branch: 'origin/master'.
>
> Why not, but we try to say "remote-tracking branch" instead of just
> "tracking". Adding "remote-" in your wording may make the line a bit
> long, but it may be sufficient to say
>
> # Your branch is identical to 'origin/master'

That's better. Thanks.

>
> That's consistant with other messages like
>
> # Your branch is ahead of '%s' by %d commits
>
> (And this would deserve a test)

Will add some test cases in t6040 if this patch has value.

-- 
Jiang Xin

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v2] status: always show tracking branch even no change
  2013-08-07 15:50 ` Matthieu Moy
  2013-08-07 16:03   ` Jiang Xin
@ 2013-08-08  5:40   ` Jiang Xin
  2013-08-08 14:49     ` [PATCH v3] " Jiang Xin
  2013-08-08 14:49     ` Jiang Xin
  1 sibling, 2 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-08  5:40 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

If the current branch has an upstream branch, and there are changes
between the current branch and its upstream, some commands (such as
"git status", "git status -bs", and "git checkout") will report their
relationship. E.g.

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    #   (use "git push" to publish your local commits)
    #
    ...

    $ git status -bs
    ## master...origin/master [ahead 1]
    ...

    $ git checkout master
    Already on 'master'
    Your branch is ahead of 'origin/master' by 1 commit.
      (use "git push" to publish your local commits)

But if there is no difference between the current branch and its
upstream, the relationship will not be reported, and it's hard to
tell whether the current branch has a tracking branch or not. And
what's worse, when the 'push.default' config variable is set to
`matching`, it's hard to tell whether the current branch has already
been pushed out or not at all [1].

With this patch, "git status" will report relationship between the
current branch and its upstream counterpart even if there is no
difference.

    $ git status
    # On branch master
    # Your branch is identical to 'origin/master'.
    #
    ...

    $ git status -bs
    ## master...origin/master
    ...

    $ git checkout master
    Already on 'master'
    Your branch is identical to 'origin/master'.

[1]: http://thread.gmane.org/gmane.comp.version-control.git/198703

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 remote.c                 | 22 ++++++++++++++------
 t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----
 wt-status.c              | 13 +++++++++---
 3 files changed, 76 insertions(+), 13 deletions(-)

diff --git a/remote.c b/remote.c
index 2433467..825f278 100644
--- a/remote.c
+++ b/remote.c
@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
+	/* Set both num_theirs and num_ours as undetermined. */
+	*num_theirs = -1;
+	*num_ours = -1;
+
 	/*
 	 * Nothing to report unless we are marked to build on top of
 	 * somebody else.
@@ -1758,14 +1762,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	theirs = lookup_commit_reference(sha1);
 	if (!theirs)
 		return 0;
+	*num_theirs = 0;
 
 	if (read_ref(branch->refname, sha1))
 		return 0;
 	ours = lookup_commit_reference(sha1);
 	if (!ours)
 		return 0;
+	*num_ours = 0;
 
-	/* are we the same? */
+	/* are we the same? both num_theirs and num_ours have been set to 0. */
 	if (theirs == ours)
 		return 0;
 
@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	prepare_revision_walk(&revs);
 
 	/* ... and count the commits on each side. */
-	*num_ours = 0;
-	*num_theirs = 0;
 	while (1) {
 		struct commit *c = get_revision(&revs);
 		if (!c)
@@ -1812,12 +1816,18 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 	int num_ours, num_theirs;
 	const char *base;
 
-	if (!stat_tracking_info(branch, &num_ours, &num_theirs))
-		return 0;
+	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
+		if (num_ours || num_theirs)
+			return 0;
+	}
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!num_theirs) {
+	if (!num_ours && !num_theirs) {
+		strbuf_addf(sb,
+			_("Your branch is identical to '%s'.\n"),
+			base);
+	} else if (!num_theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ec2b516..eafce7d 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -28,18 +28,20 @@ test_expect_success setup '
 		git reset --hard HEAD^ &&
 		git checkout -b b4 origin &&
 		advance e &&
-		advance f
+		advance f &&
+		git checkout -b b5 origin
 	) &&
 	git checkout -b follower --track master &&
 	advance g
 '
 
-script='s/^..\(b.\)[	 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
+script='s/^..\(b.\)[	 0-9a-f]*\(\[\([^]]*\)\]\)\{0,1\}.*/\1 \3/p'
 cat >expect <<\EOF
 b1 ahead 1, behind 1
 b2 ahead 1, behind 1
 b3 behind 1
 b4 ahead 2
+b5 
 EOF
 
 test_expect_success 'branch -v' '
@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '
 	test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
 	(
 		cd test && git checkout b1
 	) >actual &&
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'checkout (identical to upstream)' '
+	(
+		cd test && git checkout b5
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .origin/master" actual
+'
+
 test_expect_success 'checkout with local tracked branch' '
 	git checkout master &&
 	git checkout follower >actual &&
 	test_i18ngrep "is ahead of" actual
 '
 
-test_expect_success 'status' '
+test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
 		git checkout b1 >/dev/null &&
@@ -90,6 +100,42 @@ test_expect_success 'status' '
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'status (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		# reports nothing to commit
+		test_must_fail git commit --dry-run
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .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...origin/master
+EOF
+
+test_expect_success 'status -s -b (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		git status -s -b | head -1
+	) >actual &&
+	test_i18ncmp expect actual
+'
+
 test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index ff4b324..56f3c19 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1381,9 +1381,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	if (s->is_initial)
 		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);
-		fputc(s->null_termination ? '\0' : '\n', s->fp);
-		return;
+		if (num_ours || num_theirs) {
+			color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+			fputc(s->null_termination ? '\0' : '\n', s->fp);
+			return;
+		}
 	}
 
 	base = branch->merge[0]->dst;
@@ -1392,6 +1394,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, header_color, "...");
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
+	if (!num_ours && !num_theirs) {
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+
 	color_fprintf(s->fp, header_color, " [");
 	if (!num_ours) {
 		color_fprintf(s->fp, header_color, _("behind "));
-- 
1.8.4.rc1.429.geed1a03

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v3] status: always show tracking branch even no change
  2013-08-08  5:40   ` [PATCH v2] status: always show tracking branch even no change Jiang Xin
@ 2013-08-08 14:49     ` Jiang Xin
  2013-08-08 14:49     ` Jiang Xin
  1 sibling, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-08 14:49 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

Changes since v2:

 * The return value of function stat_tracking_info() is changed.
   When the current branch and its remote tracking branch point
   to the same commit, will return 1, instead of 0. Because we
   want to report the tracking info for such case.

 * Remove duplicated codes in builtin/branch.c, and make it simpler.

Jiang Xin (1):
  status: always show tracking branch even no change

 builtin/branch.c         | 18 +++++-----------
 remote.c                 | 18 +++++++++++-----
 t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----
 wt-status.c              |  5 +++++
 4 files changed, 73 insertions(+), 22 deletions(-)

-- 
1.8.4.rc1.430.g417e2f3

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v3] status: always show tracking branch even no change
  2013-08-08  5:40   ` [PATCH v2] status: always show tracking branch even no change Jiang Xin
  2013-08-08 14:49     ` [PATCH v3] " Jiang Xin
@ 2013-08-08 14:49     ` Jiang Xin
  2013-08-09 21:18       ` Junio C Hamano
  1 sibling, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-08 14:49 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

If the current branch has an upstream branch, and there are changes
between the current branch and its upstream, some commands (such as
"git status", "git status -bs", and "git checkout") will report their
relationship. E.g.

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    #   (use "git push" to publish your local commits)
    #
    ...

    $ git status -bs
    ## master...origin/master [ahead 1]
    ...

    $ git checkout master
    Already on 'master'
    Your branch is ahead of 'origin/master' by 1 commit.
      (use "git push" to publish your local commits)

But if there is no difference between the current branch and its
upstream, the relationship will not be reported, and it's hard to
tell whether the current branch has a tracking branch or not. And
what's worse, when the 'push.default' config variable is set to
`matching`, it's hard to tell whether the current branch has already
been pushed out or not at all [1].

So always show the remote tracking branch in the output of "git status"
and other commands will help users to see where the current branch
will push to and pull from. E.g.

    $ git status
    # On branch master
    # Your branch is identical to 'origin/master'.
    #
    ...

    $ git status -bs
    ## master...origin/master
    ...

    $ git checkout master
    Already on 'master'
    Your branch is identical to 'origin/master'.

This patch changes the return value of function stat_tracking_info().
When the current branch and its remote tracking branch point to the
same commit, will return 1, instead of 0. Because we want to report
the tracking info for such case. Also add some test cases in t6040.

[1]: http://thread.gmane.org/gmane.comp.version-control.git/198703

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/branch.c         | 18 +++++-----------
 remote.c                 | 18 +++++++++++-----
 t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----
 wt-status.c              |  5 +++++
 4 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0836890..359e75d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
 
-	if (!stat_tracking_info(branch, &ours, &theirs)) {
-		if (branch && branch->merge && branch->merge[0]->dst &&
-		    show_upstream_ref) {
-			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);
-		}
+	if (!stat_tracking_info(branch, &ours, &theirs))
 		return;
-	}
 
 	if (show_upstream_ref) {
 		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
@@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours) {
+	if (!ours && !theirs) {
+		if (ref)
+			strbuf_addf(stat, _("[%s]"), fancy.buf);
+	} else if (!ours) {
 		if (ref)
 			strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
 		else
diff --git a/remote.c b/remote.c
index 2433467..79766df 100644
--- a/remote.c
+++ b/remote.c
@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
+	/* Set both num_theirs and num_ours as undetermined. */
+	*num_theirs = -1;
+	*num_ours = -1;
+
 	/*
 	 * Nothing to report unless we are marked to build on top of
 	 * somebody else.
@@ -1758,16 +1762,18 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	theirs = lookup_commit_reference(sha1);
 	if (!theirs)
 		return 0;
+	*num_theirs = 0;
 
 	if (read_ref(branch->refname, sha1))
 		return 0;
 	ours = lookup_commit_reference(sha1);
 	if (!ours)
 		return 0;
+	*num_ours = 0;
 
-	/* are we the same? */
+	/* are we the same? both num_theirs and num_ours have been set to 0. */
 	if (theirs == ours)
-		return 0;
+		return 1;
 
 	/* Run "rev-list --left-right ours...theirs" internally... */
 	rev_argc = 0;
@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	prepare_revision_walk(&revs);
 
 	/* ... and count the commits on each side. */
-	*num_ours = 0;
-	*num_theirs = 0;
 	while (1) {
 		struct commit *c = get_revision(&revs);
 		if (!c)
@@ -1817,7 +1821,11 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!num_theirs) {
+	if (!num_ours && !num_theirs) {
+		strbuf_addf(sb,
+			_("Your branch is identical to '%s'.\n"),
+			base);
+	} else if (!num_theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ec2b516..eafce7d 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -28,18 +28,20 @@ test_expect_success setup '
 		git reset --hard HEAD^ &&
 		git checkout -b b4 origin &&
 		advance e &&
-		advance f
+		advance f &&
+		git checkout -b b5 origin
 	) &&
 	git checkout -b follower --track master &&
 	advance g
 '
 
-script='s/^..\(b.\)[	 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
+script='s/^..\(b.\)[	 0-9a-f]*\(\[\([^]]*\)\]\)\{0,1\}.*/\1 \3/p'
 cat >expect <<\EOF
 b1 ahead 1, behind 1
 b2 ahead 1, behind 1
 b3 behind 1
 b4 ahead 2
+b5 
 EOF
 
 test_expect_success 'branch -v' '
@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '
 	test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
 	(
 		cd test && git checkout b1
 	) >actual &&
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'checkout (identical to upstream)' '
+	(
+		cd test && git checkout b5
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .origin/master" actual
+'
+
 test_expect_success 'checkout with local tracked branch' '
 	git checkout master &&
 	git checkout follower >actual &&
 	test_i18ngrep "is ahead of" actual
 '
 
-test_expect_success 'status' '
+test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
 		git checkout b1 >/dev/null &&
@@ -90,6 +100,42 @@ test_expect_success 'status' '
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'status (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		# reports nothing to commit
+		test_must_fail git commit --dry-run
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .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...origin/master
+EOF
+
+test_expect_success 'status -s -b (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		git status -s -b | head -1
+	) >actual &&
+	test_i18ncmp expect actual
+'
+
 test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index ff4b324..39742ff 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1392,6 +1392,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, header_color, "...");
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
+	if (!num_ours && !num_theirs) {
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+
 	color_fprintf(s->fp, header_color, " [");
 	if (!num_ours) {
 		color_fprintf(s->fp, header_color, _("behind "));
-- 
1.8.4.rc1.430.g417e2f3

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v3] status: always show tracking branch even no change
  2013-08-08 14:49     ` Jiang Xin
@ 2013-08-09 21:18       ` Junio C Hamano
  2013-08-10 15:05         ` Jiang Xin
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2013-08-09 21:18 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> If the current branch has an upstream branch, and there are changes
> between the current branch and its upstream, some commands (such as
> "git status", "git status -bs", and "git checkout") will report their
> relationship. E.g.
>
>     $ git status
>     # On branch master
>     # Your branch is ahead of 'origin/master' by 1 commit.
>     #   (use "git push" to publish your local commits)
>     #
>     ...
>
>     $ git status -bs
>     ## master...origin/master [ahead 1]
>     ...
>
>     $ git checkout master
>     Already on 'master'
>     Your branch is ahead of 'origin/master' by 1 commit.
>       (use "git push" to publish your local commits)
>
> But if there is no difference between the current branch and its
> upstream, the relationship will not be reported, and it's hard to
> tell whether the current branch has a tracking branch or not. And
> what's worse, when the 'push.default' config variable is set to
> `matching`, it's hard to tell whether the current branch has already
> been pushed out or not at all [1].

That description of the problem you are trying to solve makes (sort
of) sense.

> So always show the remote tracking branch in the output of "git status"
> and other commands will help users to see where the current branch
> will push to and pull from. E.g.
>
>     $ git status
>     # On branch master
>     # Your branch is identical to 'origin/master'.
>     #
>     ...
>
>     $ git status -bs
>     ## master...origin/master
>     ...

Hmmph.

I do not know if this will help any case you described above, even
though this might help some other cases.  The added output is to
always show the current branch and its upstream, but the thing is,
the original issue in $gmane/198703 was *not* that the current
branch was pushed and up to date.  It was that there was no current
branch to be pushed.  The same thing would happen if you are on a
local branch that is not set to be pushed to the other side
(e.g. the configuration is set to "matching" and there is no such
branch on the other end).

"Your branch is identical to" will be given only if your branch is
set to be pushed out, no?  For the user to tell what is going on,
the user has to notice the lack of this extra line in the output,
and noticing the lack of anything is much unlikely.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3] status: always show tracking branch even no change
  2013-08-09 21:18       ` Junio C Hamano
@ 2013-08-10 15:05         ` Jiang Xin
  2013-08-12  6:15           ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-10 15:05 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

2013/8/10 Junio C Hamano <gitster@pobox.com>:
> Jiang Xin <worldhello.net@gmail.com> writes:
>
>> So always show the remote tracking branch in the output of "git status"
>> and other commands will help users to see where the current branch
>> will push to and pull from. E.g.
>> ...
>
> Hmmph.
>
> I do not know if this will help any case you described above, even
> though this might help some other cases.  The added output is to
> always show the current branch and its upstream, but the thing is,
> the original issue in $gmane/198703 was *not* that the current
> branch was pushed and up to date.  It was that there was no current
> branch to be pushed.  The same thing would happen if you are on a
> local branch that is not set to be pushed to the other side
> (e.g. the configuration is set to "matching" and there is no such
> branch on the other end).
>

How about write the commit log like this:

-- 8< --
From: Jiang Xin <worldhello.net@gmail.com>
Date: Wed, 7 Aug 2013 21:45:01 +0800
Subject: [PATCH v4] status: always show tracking branch even no change

If the current branch has an upstream branch, and there are changes
between the current branch and its upstream, some commands (such as
"git status", "git status -bs", and "git checkout") will report their
relationship. E.g.

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    ...

    $ git status -bs
    ## master...origin/master [ahead 1]
    ...

    $ git checkout master
    Already on 'master'
    Your branch is ahead of 'origin/master' by 1 commit.
    ...

With this patch, the relationship between the current branch its
upstream will be reported always even if there is no difference
between them. E.g.

    $ git status
    # On branch master
    # Your branch is identical to 'origin/master'.
    ...

    $ git status -bs
    ## master...origin/master
    ...

    $ git checkout master
    Already on 'master'
    Your branch is identical to 'origin/master'.
    ...

Then if there is no tracking info reported, the user may need to do
something. Maybe the current branch is a new branch that needs to be
pushed out, or maybe it's a branch which should add remote tracking
settings.

This patch changes the return value of function stat_tracking_info()
from 0 (not report) to 1 (report), when the current branch and its
remote tracking branch point to the same commit. Also add some test
cases in t6040.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/branch.c         | 18 +++++-----------
 remote.c                 | 18 +++++++++++-----
 t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----
 wt-status.c              |  5 +++++
 4 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0836890..359e75d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
 
-	if (!stat_tracking_info(branch, &ours, &theirs)) {
-		if (branch && branch->merge && branch->merge[0]->dst &&
-		    show_upstream_ref) {
-			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);
-		}
+	if (!stat_tracking_info(branch, &ours, &theirs))
 		return;
-	}
 
 	if (show_upstream_ref) {
 		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
@@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours) {
+	if (!ours && !theirs) {
+		if (ref)
+			strbuf_addf(stat, _("[%s]"), fancy.buf);
+	} else if (!ours) {
 		if (ref)
 			strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
 		else
diff --git a/remote.c b/remote.c
index 2433467..79766df 100644
--- a/remote.c
+++ b/remote.c
@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
+	/* Set both num_theirs and num_ours as undetermined. */
+	*num_theirs = -1;
+	*num_ours = -1;
+
 	/*
 	 * Nothing to report unless we are marked to build on top of
 	 * somebody else.
@@ -1758,16 +1762,18 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	theirs = lookup_commit_reference(sha1);
 	if (!theirs)
 		return 0;
+	*num_theirs = 0;
 
 	if (read_ref(branch->refname, sha1))
 		return 0;
 	ours = lookup_commit_reference(sha1);
 	if (!ours)
 		return 0;
+	*num_ours = 0;
 
-	/* are we the same? */
+	/* are we the same? both num_theirs and num_ours have been set to 0. */
 	if (theirs == ours)
-		return 0;
+		return 1;
 
 	/* Run "rev-list --left-right ours...theirs" internally... */
 	rev_argc = 0;
@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	prepare_revision_walk(&revs);
 
 	/* ... and count the commits on each side. */
-	*num_ours = 0;
-	*num_theirs = 0;
 	while (1) {
 		struct commit *c = get_revision(&revs);
 		if (!c)
@@ -1817,7 +1821,11 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!num_theirs) {
+	if (!num_ours && !num_theirs) {
+		strbuf_addf(sb,
+			_("Your branch is identical to '%s'.\n"),
+			base);
+	} else if (!num_theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ec2b516..eafce7d 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -28,18 +28,20 @@ test_expect_success setup '
 		git reset --hard HEAD^ &&
 		git checkout -b b4 origin &&
 		advance e &&
-		advance f
+		advance f &&
+		git checkout -b b5 origin
 	) &&
 	git checkout -b follower --track master &&
 	advance g
 '
 
-script='s/^..\(b.\)[	 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
+script='s/^..\(b.\)[	 0-9a-f]*\(\[\([^]]*\)\]\)\{0,1\}.*/\1 \3/p'
 cat >expect <<\EOF
 b1 ahead 1, behind 1
 b2 ahead 1, behind 1
 b3 behind 1
 b4 ahead 2
+b5 
 EOF
 
 test_expect_success 'branch -v' '
@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '
 	test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
 	(
 		cd test && git checkout b1
 	) >actual &&
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'checkout (identical to upstream)' '
+	(
+		cd test && git checkout b5
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .origin/master" actual
+'
+
 test_expect_success 'checkout with local tracked branch' '
 	git checkout master &&
 	git checkout follower >actual &&
 	test_i18ngrep "is ahead of" actual
 '
 
-test_expect_success 'status' '
+test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
 		git checkout b1 >/dev/null &&
@@ -90,6 +100,42 @@ test_expect_success 'status' '
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'status (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		# reports nothing to commit
+		test_must_fail git commit --dry-run
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .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...origin/master
+EOF
+
+test_expect_success 'status -s -b (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		git status -s -b | head -1
+	) >actual &&
+	test_i18ncmp expect actual
+'
+
 test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index ff4b324..39742ff 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1392,6 +1392,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, header_color, "...");
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
+	if (!num_ours && !num_theirs) {
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+
 	color_fprintf(s->fp, header_color, " [");
 	if (!num_ours) {
 		color_fprintf(s->fp, header_color, _("behind "));
-- 
1.8.4.rc1.430.g417e2f3

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v3] status: always show tracking branch even no change
  2013-08-10 15:05         ` Jiang Xin
@ 2013-08-12  6:15           ` Junio C Hamano
  2013-08-13  4:49             ` Jiang Xin
  0 siblings, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2013-08-12  6:15 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> 2013/8/10 Junio C Hamano <gitster@pobox.com>:
>> Jiang Xin <worldhello.net@gmail.com> writes:
>>
>>> So always show the remote tracking branch in the output of "git status"
>>> and other commands will help users to see where the current branch
>>> will push to and pull from. E.g.
>>> ...
>>
>> Hmmph.
>>
>> I do not know if this will help any case you described above, even
>> though this might help some other cases.  The added output is to
>> always show the current branch and its upstream, but the thing is,
>> the original issue in $gmane/198703 was *not* that the current
>> branch was pushed and up to date.  It was that there was no current
>> branch to be pushed.  The same thing would happen if you are on a
>> local branch that is not set to be pushed to the other side
>> (e.g. the configuration is set to "matching" and there is no such
>> branch on the other end).
>>
>
> How about write the commit log like this:
> ...
> Then if there is no tracking info reported, the user may need to do
> something. Maybe the current branch is a new branch that needs to be
> pushed out, or maybe it's a branch which should add remote tracking
> settings.

Would that help anybody, though?

A user who does not notice the _lack_ of mention of the current
branch in the feedback from "git push" would not notice the lack of
"ahead, behind or the same".

We could contemplate on saying "your current branch is not set to be
pushed out to anywhere" instead of being silent in the case where
the output with your patch is silent, but that would make "status"
output irritatingly chatty when you are on a private topic branch
that you never intend to push out except as a part of an integration
branch after merging into it, so it is not a good solution either,
but at least that would solve the original problem.

Isn't it the real solution to the original poster's problem to make
"git push" explain "Everything is up to date, and nothing is pushed"
case better?

Perhaps "git push" can learn an option to show what the command
would push out if there were something to push.  If push.default is
set to matching and the user is on a branch that does not exist on
the receiving end, matching branches will be listed as "up to date"
and the user could notice that his current branch is _not_ among the
ones that are listed.  When there is _no_ branch to be pushed out
(e.g. there is no matching branches, or you are on a detached HEAD)
that "please explain" option could really explain whey there is no
branch to be pushed out".

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v3] status: always show tracking branch even no change
  2013-08-12  6:15           ` Junio C Hamano
@ 2013-08-13  4:49             ` Jiang Xin
  2013-08-13  4:53               ` [PATCH v5 1/2] branch: not report invalid tracking branch Jiang Xin
  2013-08-13  4:53               ` [PATCH v5 2/2] " Jiang Xin
  0 siblings, 2 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-13  4:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Matthieu Moy, Git List

2013/8/12 Junio C Hamano <gitster@pobox.com>:
> Jiang Xin <worldhello.net@gmail.com> writes:
>
>> 2013/8/10 Junio C Hamano <gitster@pobox.com>:
>>> Jiang Xin <worldhello.net@gmail.com> writes:
>>>
>>>> So always show the remote tracking branch in the output of "git status"
>>>> and other commands will help users to see where the current branch
>>>> will push to and pull from. E.g.
>>>> ...
>>>
>>> Hmmph.
>>>
>>> I do not know if this will help any case you described above, even
>>> though this might help some other cases.  The added output is to
>>> always show the current branch and its upstream, but the thing is,
>>> the original issue in $gmane/198703 was *not* that the current
>>> branch was pushed and up to date.  It was that there was no current
>>> branch to be pushed.  The same thing would happen if you are on a
>>> local branch that is not set to be pushed to the other side
>>> (e.g. the configuration is set to "matching" and there is no such
>>> branch on the other end).
>>>
>>
>> How about write the commit log like this:
>> ...
>> Then if there is no tracking info reported, the user may need to do
>> something. Maybe the current branch is a new branch that needs to be
>> pushed out, or maybe it's a branch which should add remote tracking
>> settings.
>
> Would that help anybody, though?

I will split the patch into two. The 1st patch resolves a real problem:

    branch: not report invalid tracking branch

    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 whether the upstream branch
    does not exist, or nothing is changed between one branch and its
    upstream.

    This patch changes the return value of function stat_tracking_info().
    Only returns false when there is no tracking branch or the tracking
    branch is invalid, otherwise true. 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.

And in the 2nd patch, I will not mention "git push" (current not be
pushed out ...) any more, and only focus on "git status". It's just
a suggestion, may only fit small group of users' taste.


-- 
Jiang Xin

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v5 1/2] branch: not report invalid tracking branch
  2013-08-13  4:49             ` Jiang Xin
@ 2013-08-13  4:53               ` Jiang Xin
  2013-08-14 15:21                 ` Junio C Hamano
  2013-08-14 15:38                 ` Junio C Hamano
  2013-08-13  4:53               ` [PATCH v5 2/2] " Jiang Xin
  1 sibling, 2 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-13  4:53 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

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 whether the upstream branch
does not exist, or nothing is changed between one branch and its
upstream.

This patch changes the return value of function stat_tracking_info().
Only returns false when there is no tracking branch or the tracking
branch is invalid, otherwise true. 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.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/branch.c | 18 +++++-------------
 remote.c         | 24 ++++++++++++------------
 wt-status.c      | 13 +++++++++++--
 3 files changed, 28 insertions(+), 27 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0836890..359e75d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
 
-	if (!stat_tracking_info(branch, &ours, &theirs)) {
-		if (branch && branch->merge && branch->merge[0]->dst &&
-		    show_upstream_ref) {
-			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);
-		}
+	if (!stat_tracking_info(branch, &ours, &theirs))
 		return;
-	}
 
 	if (show_upstream_ref) {
 		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
@@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours) {
+	if (!ours && !theirs) {
+		if (ref)
+			strbuf_addf(stat, _("[%s]"), fancy.buf);
+	} else if (!ours) {
 		if (ref)
 			strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
 		else
diff --git a/remote.c b/remote.c
index 2433467..c747936 100644
--- a/remote.c
+++ b/remote.c
@@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 }
 
 /*
- * Return true if there is anything to report, otherwise false.
+ * Return false if cannot stat a tracking branch (not exist or invalid),
+ * otherwise true.
  */
 int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 {
@@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
-	/*
-	 * Nothing to report unless we are marked to build on top of
-	 * somebody else.
-	 */
+	/* False unless we are marked to build on top of somebody else. */
 	if (!branch ||
 	    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
 		return 0;
 
-	/*
-	 * If what we used to build on no longer exists, there is
-	 * nothing to report.
-	 */
+	/* False if what we used to build on no longer exists */
 	base = branch->merge[0]->dst;
 	if (read_ref(base, sha1))
 		return 0;
@@ -1765,9 +1760,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	if (!ours)
 		return 0;
 
+	*num_theirs = 0;
+	*num_ours = 0;
+
 	/* are we the same? */
 	if (theirs == ours)
-		return 0;
+		return 1;
 
 	/* Run "rev-list --left-right ours...theirs" internally... */
 	rev_argc = 0;
@@ -1786,8 +1784,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	prepare_revision_walk(&revs);
 
 	/* ... and count the commits on each side. */
-	*num_ours = 0;
-	*num_theirs = 0;
 	while (1) {
 		struct commit *c = get_revision(&revs);
 		if (!c)
@@ -1815,6 +1811,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 	if (!stat_tracking_info(branch, &num_ours, &num_theirs))
 		return 0;
 
+	/* Nothing to report if neither side has changes. */
+	if (!num_ours && !num_theirs)
+		return 0;
+
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
 	if (!num_theirs) {
diff --git a/wt-status.c b/wt-status.c
index ff4b324..0c6a3a5 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	branch = branch_get(s->branch + 11);
 	if (s->is_initial)
 		color_fprintf(s->fp, header_color, _("Initial commit on "));
+
+	color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+
+	/*
+	 * Not report tracking info if no tracking branch found
+	 * or no difference found.
+	 */
 	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
-		color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+	if (!num_ours && !num_theirs) {
 		fputc(s->null_termination ? '\0' : '\n', s->fp);
 		return;
 	}
 
 	base = branch->merge[0]->dst;
 	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, branch_color_remote, "%s", base);
 
-- 
1.8.4.rc1.430.g417e2f3

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 2/2] status: always show tracking branch even no change
  2013-08-13  4:49             ` Jiang Xin
  2013-08-13  4:53               ` [PATCH v5 1/2] branch: not report invalid tracking branch Jiang Xin
@ 2013-08-13  4:53               ` Jiang Xin
  1 sibling, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-13  4:53 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

In order to see what the current branch is tracking, one way is using
"git branch -v -v", but branches other than the current are also
reported. Another way is using "git status", such as:

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    ...

But this will not work if there is no change between the current
branch and its upstream. What if report upstream tracking info
always even if there is no difference. E.g.

    $ git status
    # On branch feature1
    # Your branch is identical to 'github/feature1'.
    ...

    $ git status -bs
    ## feature1...github/feature1
    ...

    $ git checkout feature1
    Already on 'feature1'
    Your branch is identical to 'github/feature1'.
    ...

Also add some test cases in t6040.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 remote.c                 | 10 ++++-----
 t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----
 wt-status.c              | 13 +++++-------
 3 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/remote.c b/remote.c
index c747936..70307f4 100644
--- a/remote.c
+++ b/remote.c
@@ -1811,13 +1811,13 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 	if (!stat_tracking_info(branch, &num_ours, &num_theirs))
 		return 0;
 
-	/* Nothing to report if neither side has changes. */
-	if (!num_ours && !num_theirs)
-		return 0;
-
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!num_theirs) {
+	if (!num_ours && !num_theirs) {
+		strbuf_addf(sb,
+			_("Your branch is identical to '%s'.\n"),
+			base);
+	} else if (!num_theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ec2b516..eafce7d 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -28,18 +28,20 @@ test_expect_success setup '
 		git reset --hard HEAD^ &&
 		git checkout -b b4 origin &&
 		advance e &&
-		advance f
+		advance f &&
+		git checkout -b b5 origin
 	) &&
 	git checkout -b follower --track master &&
 	advance g
 '
 
-script='s/^..\(b.\)[	 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
+script='s/^..\(b.\)[	 0-9a-f]*\(\[\([^]]*\)\]\)\{0,1\}.*/\1 \3/p'
 cat >expect <<\EOF
 b1 ahead 1, behind 1
 b2 ahead 1, behind 1
 b3 behind 1
 b4 ahead 2
+b5 
 EOF
 
 test_expect_success 'branch -v' '
@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '
 	test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
 	(
 		cd test && git checkout b1
 	) >actual &&
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'checkout (identical to upstream)' '
+	(
+		cd test && git checkout b5
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .origin/master" actual
+'
+
 test_expect_success 'checkout with local tracked branch' '
 	git checkout master &&
 	git checkout follower >actual &&
 	test_i18ngrep "is ahead of" actual
 '
 
-test_expect_success 'status' '
+test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
 		git checkout b1 >/dev/null &&
@@ -90,6 +100,42 @@ test_expect_success 'status' '
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'status (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		# reports nothing to commit
+		test_must_fail git commit --dry-run
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .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...origin/master
+EOF
+
+test_expect_success 'status -s -b (identical to upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		git status -s -b | head -1
+	) >actual &&
+	test_i18ncmp expect actual
+'
+
 test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index 0c6a3a5..627b59e 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1383,24 +1383,21 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 
 	color_fprintf(s->fp, branch_color_local, "%s", branch_name);
 
-	/*
-	 * Not report tracking info if no tracking branch found
-	 * or no difference found.
-	 */
 	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
 		fputc(s->null_termination ? '\0' : '\n', s->fp);
 		return;
 	}
-	if (!num_ours && !num_theirs) {
-		fputc(s->null_termination ? '\0' : '\n', s->fp);
-		return;
-	}
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
 	color_fprintf(s->fp, header_color, "...");
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
+	if (!num_ours && !num_theirs) {
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+
 	color_fprintf(s->fp, header_color, " [");
 	if (!num_ours) {
 		color_fprintf(s->fp, header_color, _("behind "));
-- 
1.8.4.rc1.430.g417e2f3

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 1/2] branch: not report invalid tracking branch
  2013-08-13  4:53               ` [PATCH v5 1/2] branch: not report invalid tracking branch Jiang Xin
@ 2013-08-14 15:21                 ` Junio C Hamano
  2013-08-15  2:14                   ` Jiang Xin
  2013-08-14 15:38                 ` Junio C Hamano
  1 sibling, 1 reply; 36+ messages in thread
From: Junio C Hamano @ 2013-08-14 15:21 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> 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 whether the upstream branch
> does not exist, or nothing is changed between one branch and its
> upstream.
>
> This patch changes the return value of function stat_tracking_info().
> Only returns false when there is no tracking branch or the tracking
> branch is invalid, otherwise true. 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.
>
> Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
> ---
>  builtin/branch.c | 18 +++++-------------
>  remote.c         | 24 ++++++++++++------------
>  wt-status.c      | 13 +++++++++++--
>  3 files changed, 28 insertions(+), 27 deletions(-)
>
> diff --git a/builtin/branch.c b/builtin/branch.c
> index 0836890..359e75d 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
>  	struct branch *branch = branch_get(branch_name);
>  	struct strbuf fancy = STRBUF_INIT;
>  
> -	if (!stat_tracking_info(branch, &ours, &theirs)) {
> -		if (branch && branch->merge && branch->merge[0]->dst &&
> -		    show_upstream_ref) {
> -			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);
> -		}
> +	if (!stat_tracking_info(branch, &ours, &theirs))
>  		return;
> -	}
>  
>  	if (show_upstream_ref) {
>  		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
> @@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
>  			strbuf_addstr(&fancy, ref);
>  	}
>  
> -	if (!ours) {
> +	if (!ours && !theirs) {
> +		if (ref)
> +			strbuf_addf(stat, _("[%s]"), fancy.buf);

Mental note: the updated stat_tracking_info() says "something to
report exists" when the current branch and its @{u} are the same,
and we report the branch here.

> +	} else if (!ours) {
>  		if (ref)
>  			strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);

This is not a fault of your change, but the logic to show the
upstream ref is unnecessarily unclear due to variable cascading.
The master switch "show_upstream_ref" is what is used to ask this to
fill the name of the upstream ref, and "ref" is made non-NULL only
when "show_upstream_ref" is true.  Also "fancy" would be non-empty
only in that case, so this "if (ref)" could be any one of these:

        if (show_upstream_ref)
	if (ref)
        if (fancy.len)

It is disturbing that the middle one is used.  If you take the
stance that the code should reflect the logic, the first one
(i.e. "we were asked to show upstream ref, so we show it here")
makes the most sense.  If you take the stance that the code should
be safe with the low-level implementation, the last one (i.e. "we
are showing what is in fancy, if we have prepared something to show
in that buffer") makes sense.  The middle one is the least logical
thing to base the decision on.

> diff --git a/remote.c b/remote.c
> index 2433467..c747936 100644
> --- a/remote.c
> +++ b/remote.c
> @@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
>  }
>  
>  /*
> - * Return true if there is anything to report, otherwise false.
> + * Return false if cannot stat a tracking branch (not exist or invalid),
> + * otherwise true.
>   */
>  int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
>  {
> @@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
>  	const char *rev_argv[10], *base;
>  	int rev_argc;
>  
> -	/*
> -	 * Nothing to report unless we are marked to build on top of
> -	 * somebody else.
> -	 */
> +	/* False unless we are marked to build on top of somebody else. */

Aren't these saying the same thing?  I'd rather see the comment say
"nothing/something to report", instead of "false/true".  The latter
can be read from the value returned in the code, and writing that in
the comment is redundant.  The former tells the reader what that
"false" _means_, which is the whole point of adding a comment.

>  	if (!branch ||
>  	    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
>  		return 0;
>  
> -	/*
> -	 * If what we used to build on no longer exists, there is
> -	 * nothing to report.
> -	 */
> +	/* False if what we used to build on no longer exists */
>  	base = branch->merge[0]->dst;
>  	if (read_ref(base, sha1))
>  		return 0;

Likewise.

> +	*num_theirs = 0;
> +	*num_ours = 0;
> +
>  	/* are we the same? */
>  	if (theirs == ours)
> -		return 0;
> +		return 1;

Shouldn't these zero assignments belong to this condition?  I.e.

	if (theirs == ours) {
        	*num_theirs = *num_ours = 0;
                return 1;
	}

> @@ -1786,8 +1784,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
>  	prepare_revision_walk(&revs);
>  
>  	/* ... and count the commits on each side. */
> -	*num_ours = 0;
> -	*num_theirs = 0;
>  	while (1) {
>  		struct commit *c = get_revision(&revs);
>  		if (!c)
> @@ -1815,6 +1811,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
>  	if (!stat_tracking_info(branch, &num_ours, &num_theirs))
>  		return 0;
>  
> +	/* Nothing to report if neither side has changes. */
> +	if (!num_ours && !num_theirs)
> +		return 0;

As far as I can tell, all callers of stat_tracking_info() pass
non-NULL pointers to these two parameters, with or without your
patch.  Can this ever trigger?

The changes you made to builtin/branch.c seems to expect that
returned *num_ours and *num_theirs could both be 0, so it does not
look like the above is a typo of

	if (!*num_ours && !*num_theirs)
        	return 0;

even though the comment "neither side has changes" seems to indicate
that was what was meant.

I am puzzled by this incoherence between the callers and the callee.

> diff --git a/wt-status.c b/wt-status.c
> index ff4b324..0c6a3a5 100644
> --- a/wt-status.c
> +++ b/wt-status.c
> @@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
>  	branch = branch_get(s->branch + 11);
>  	if (s->is_initial)
>  		color_fprintf(s->fp, header_color, _("Initial commit on "));
> +
> +	color_fprintf(s->fp, branch_color_local, "%s", branch_name);
> +
> +	/*
> +	 * Not report tracking info if no tracking branch found
> +	 * or no difference found.
> +	 */
>  	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
> -		color_fprintf(s->fp, branch_color_local, "%s", branch_name);
> +		fputc(s->null_termination ? '\0' : '\n', s->fp);
> +		return;
> +	}
> +	if (!num_ours && !num_theirs) {
>  		fputc(s->null_termination ? '\0' : '\n', s->fp);
>  		return;
>  	}
>  
>  	base = branch->merge[0]->dst;
>  	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, branch_color_remote, "%s", base);

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 1/2] branch: not report invalid tracking branch
  2013-08-13  4:53               ` [PATCH v5 1/2] branch: not report invalid tracking branch Jiang Xin
  2013-08-14 15:21                 ` Junio C Hamano
@ 2013-08-14 15:38                 ` Junio C Hamano
  2013-08-15 18:11                   ` [PATCH v6 1/3] " Jiang Xin
                                     ` (2 more replies)
  1 sibling, 3 replies; 36+ messages in thread
From: Junio C Hamano @ 2013-08-14 15:38 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> 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 whether the upstream branch
> does not exist, or nothing is changed between one branch and its
> upstream.

I am guessing that by "invalid", you used to have another branch
(possibly a remote one) you built a branch on (hence the upstream of
the latter is set to the former) and the former branch no longer
exists.

Shouldn't that case reported a bit more specially?  After doing this:

	git init
        git commit --allow-empty -m initial ;# on master
        git branch topicbase
        git checkout -t -b topic topicbase
        git commit --allow-empty -m topic ;# on topic
        git branch -d topicbase

the branch "topic" _thinks_ it is still based on "topicbase", but of
course "git log @{u}.." will fail.

A few thought-alouds:

 - Perhaps "git branch -d topicbase" should have warned that there
   are some branches that are based on it?  Should it have failed?
   Or should it automatically removed branch.*.merge entries that
   point at it (while warning)?

 - The operation that removes the @{u} of some branch does not have
   to be "git branch -d".  It could be "remote --prune", and it does
   not make much sense to fail that operation, as what is gone from
   the other side is gone, and the point of having remote tracking
   branches is to keep a faithful copy of the observed status of the
   remote.  It implies that failing "git branch -d topicbase" is not
   a good idea.  Also removing the branch.*.merge automatically is
   probably not what the user wants (at least, the name would hint
   something, even after the topicbase branch is gone).

So "git branch -v -v [topic]" would want to still say that topic is
based on topicbranch, even though the latter is gone and there is no
longer a real "building on" relationship.

E.g. before "git branch -d topicbase" we would see something like:

    $ git branch -v -v
      master    e67ac84 initial
    * topic     3fc0f2a [topicbase: ahead 1] topic
      topicbase e67ac84 [master] initial

and after it, we currently see:

    $ git branch -v -v
      master    e67ac84 initial
    * topic     3fc0f2a [topicbase] topic
      topicbase e67ac84 [master] initial

but we may want to say:

    $ git branch -v -v
      master    e67ac84 initial
    * topic     3fc0f2a [topicbase (gone)] topic
      topicbase e67ac84 [master] initial

or something.

In order to distinguish these three cases (i.e. no tracking, with
configured but no longer valid tracking, and with tracking), you
would need more than true/false.

> This patch changes the return value of function stat_tracking_info().
> Only returns false when there is no tracking branch or the tracking
> branch is invalid, otherwise true.

Instead, you would need -1 (with "gone" base), 0 (no base), 1 (with
base).

This is a tangent, but we might want to rename stat_tracking_info().
A branch A building on top of another branch B does not mean A
"tracks" B.  The wording is a source of confusion.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 1/2] branch: not report invalid tracking branch
  2013-08-14 15:21                 ` Junio C Hamano
@ 2013-08-15  2:14                   ` Jiang Xin
  0 siblings, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-15  2:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Matthieu Moy, Git List

2013/8/14 Junio C Hamano <gitster@pobox.com>
> >  /*
> > - * Return true if there is anything to report, otherwise false.
> > + * Return false if cannot stat a tracking branch (not exist or invalid),
> > + * otherwise true.
> >   */
> >  int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
> >  {
> > @@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
> >       const char *rev_argv[10], *base;
> >       int rev_argc;
> >
> > -     /*
> > -      * Nothing to report unless we are marked to build on top of
> > -      * somebody else.
> > -      */
> > +     /* False unless we are marked to build on top of somebody else. */
>
> Aren't these saying the same thing?  I'd rather see the comment say
> "nothing/something to report", instead of "false/true".  The latter
> can be read from the value returned in the code, and writing that in
> the comment is redundant.  The former tells the reader what that
> "false" _means_, which is the whole point of adding a comment.

Maybe "Cannot stat unless ..." is better than "Nothing to report unless ...",
because this patch change the meaning of returns of stat_tracking_info().
And I have already updated the comments for this function.

>
> > +     *num_theirs = 0;
> > +     *num_ours = 0;
> > +
> >       /* are we the same? */
> >       if (theirs == ours)
> > -             return 0;
> > +             return 1;
>
> Shouldn't these zero assignments belong to this condition?  I.e.
>
>         if (theirs == ours) {
>                 *num_theirs = *num_ours = 0;
>                 return 1;
>         }

I will refactor like this,

> > @@ -1786,8 +1784,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
> >       prepare_revision_walk(&revs);
> >
> >       /* ... and count the commits on each side. */
> > -     *num_ours = 0;
> > -     *num_theirs = 0;
> >       while (1) {
> >               struct commit *c = get_revision(&revs);
> >               if (!c)

and these two variables(*num_ours and *num_theirs) have to be
initialized here again.

> > @@ -1815,6 +1811,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
> >       if (!stat_tracking_info(branch, &num_ours, &num_theirs))
> >               return 0;
> >
> > +     /* Nothing to report if neither side has changes. */
> > +     if (!num_ours && !num_theirs)
> > +             return 0;
>
> As far as I can tell, all callers of stat_tracking_info() pass
> non-NULL pointers to these two parameters, with or without your
> patch.  Can this ever trigger?
>
> The changes you made to builtin/branch.c seems to expect that
> returned *num_ours and *num_theirs could both be 0, so it does not
> look like the above is a typo of
>
>         if (!*num_ours && !*num_theirs)
>                 return 0;
>

It's really easy to make people puzzled, since these two hunks in this patch
both have two similar variables: num_ours and num_theirs. But they are
different.

In previous hunk, num_ours and num_theres are from stat_tracking_info(),
and they are pointers.

    int stat_tracking_info(struct branch *branch,
                           int *num_ours,
                           int *num_theirs)

But in this hunk, num_ours and num_theres are defined as integers in
funciton  format_tracking_info().

    int format_tracking_info(struct branch *branch, struct strbuf *sb)
    {
        int num_ours, num_theirs;

To make it clear, I should change the variables name to ours and theirs
just like function fill_tracking_info() in builtin/branch.c.

-- 
Jiang Xin

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v6 1/3] branch: not report invalid tracking branch
  2013-08-14 15:38                 ` Junio C Hamano
@ 2013-08-15 18:11                   ` Jiang Xin
  2013-08-15 18:11                   ` [PATCH v6 2/3] branch: report invalid tracking branch as broken Jiang Xin
  2013-08-15 18:11                   ` [PATCH v6 " Jiang Xin
  2 siblings, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-15 18:11 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

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 whether the upstream branch
does not exist, or nothing is changed between one branch and its
upstream.

This patch changes the return value of function stat_tracking_info().
Only returns false when there is no tracking branch or the tracking
branch is invalid, otherwise true. 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.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/branch.c         | 24 ++++++++----------------
 remote.c                 | 43 ++++++++++++++++++++++---------------------
 t/t6040-tracking-info.sh |  8 ++++++--
 wt-status.c              | 13 +++++++++++--
 4 files changed, 47 insertions(+), 41 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0903763..3e016a6 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
 
-	if (!stat_tracking_info(branch, &ours, &theirs)) {
-		if (branch && branch->merge && branch->merge[0]->dst &&
-		    show_upstream_ref) {
-			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);
-		}
+	if (!stat_tracking_info(branch, &ours, &theirs))
 		return;
-	}
 
 	if (show_upstream_ref) {
 		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
@@ -448,19 +437,22 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours) {
-		if (ref)
+	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);
 		else
 			strbuf_addf(stat, _("[behind %d]"), theirs);
 
 	} else if (!theirs) {
-		if (ref)
+		if (show_upstream_ref)
 			strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
 		else
 			strbuf_addf(stat, _("[ahead %d]"), ours);
 	} else {
-		if (ref)
+		if (show_upstream_ref)
 			strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
 				    fancy.buf, ours, theirs);
 		else
diff --git a/remote.c b/remote.c
index 2433467..26bd543 100644
--- a/remote.c
+++ b/remote.c
@@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 }
 
 /*
- * Return true if there is anything to report, otherwise false.
+ * Return false if cannot stat a tracking branch (not exist or invalid),
+ * otherwise true.
  */
 int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 {
@@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
-	/*
-	 * Nothing to report unless we are marked to build on top of
-	 * somebody else.
-	 */
+	/* Cannot stat unless we are marked to build on top of somebody else. */
 	if (!branch ||
 	    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
 		return 0;
 
-	/*
-	 * If what we used to build on no longer exists, there is
-	 * nothing to report.
-	 */
+	/* Cannot stat if what we used to build on no longer exists */
 	base = branch->merge[0]->dst;
 	if (read_ref(base, sha1))
 		return 0;
@@ -1766,8 +1761,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 		return 0;
 
 	/* are we the same? */
-	if (theirs == ours)
-		return 0;
+	if (theirs == ours) {
+		*num_theirs = *num_ours = 0;
+		return 1;
+	}
 
 	/* Run "rev-list --left-right ours...theirs" internally... */
 	rev_argc = 0;
@@ -1809,31 +1806,35 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
  */
 int format_tracking_info(struct branch *branch, struct strbuf *sb)
 {
-	int num_ours, num_theirs;
+	int ours, theirs;
 	const char *base;
 
-	if (!stat_tracking_info(branch, &num_ours, &num_theirs))
+	if (!stat_tracking_info(branch, &ours, &theirs))
+		return 0;
+
+	/* Nothing to report if neither side has changes. */
+	if (!ours && !theirs)
 		return 0;
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!num_theirs) {
+	if (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
-			   num_ours),
-			base, num_ours);
+			   ours),
+			base, ours);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git push\" to publish your local commits)\n"));
-	} else if (!num_ours) {
+	} else if (!ours) {
 		strbuf_addf(sb,
 			Q_("Your branch is behind '%s' by %d commit, "
 			       "and can be fast-forwarded.\n",
 			   "Your branch is behind '%s' by %d commits, "
 			       "and can be fast-forwarded.\n",
-			   num_theirs),
-			base, num_theirs);
+			   theirs),
+			base, theirs);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git pull\" to update your local branch)\n"));
@@ -1845,8 +1846,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 			   "Your branch and '%s' have diverged,\n"
 			       "and have %d and %d different commits each, "
 			       "respectively.\n",
-			   num_theirs),
-			base, num_ours, num_theirs);
+			   theirs),
+			base, ours, theirs);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git pull\" to merge the remote branch into yours)\n"));
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ec2b516..471dd64 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -28,10 +28,14 @@ test_expect_success setup '
 		git reset --hard HEAD^ &&
 		git checkout -b b4 origin &&
 		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 follower --track master &&
-	advance g
+	advance h
 '
 
 script='s/^..\(b.\)[	 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
diff --git a/wt-status.c b/wt-status.c
index ff4b324..0c6a3a5 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	branch = branch_get(s->branch + 11);
 	if (s->is_initial)
 		color_fprintf(s->fp, header_color, _("Initial commit on "));
+
+	color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+
+	/*
+	 * Not report tracking info if no tracking branch found
+	 * or no difference found.
+	 */
 	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
-		color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+	if (!num_ours && !num_theirs) {
 		fputc(s->null_termination ? '\0' : '\n', s->fp);
 		return;
 	}
 
 	base = branch->merge[0]->dst;
 	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, branch_color_remote, "%s", base);
 
-- 
1.8.4.rc2.478.g12f0bfd.dirty

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 2/3] branch: report invalid tracking branch as broken
  2013-08-14 15:38                 ` Junio C Hamano
  2013-08-15 18:11                   ` [PATCH v6 1/3] " Jiang Xin
@ 2013-08-15 18:11                   ` Jiang Xin
  2013-08-15 18:38                     ` Junio C Hamano
  2013-08-15 22:54                     ` Junio C Hamano
  2013-08-15 18:11                   ` [PATCH v6 " Jiang Xin
  2 siblings, 2 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-15 18:11 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

If a branch has been set to track a upstream, but the upstream branch
is missing or invalid, the tracking info is silently ignored in the
output of some commands such as "git branch -vv" and "git status",
as if there were no such tracking settings.

Junio suggested broken upstream should be reported [1]. E.g.

    $ git branch -v -v
      master    e67ac84 initial
    * topic     3fc0f2a [topicbase: broken] topic

    $ git status
    # On branch topic
    # Your branch is based on a broken ref 'topicbase'.
    #   (use "git branch --unset-upstream" to fixup)
    ...

    $ git status -b -s
    ## topic...topicbase [broken]
    ...

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).

[1]: http://thread.gmane.org/gmane.comp.version-control.git/231830/focus=232288

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/branch.c         | 17 +++++++++++++++--
 remote.c                 | 43 ++++++++++++++++++++++++++++++------------
 t/t6040-tracking-info.sh | 49 ++++++++++++++++++++++++++++++++++++++++++++++--
 wt-status.c              | 27 ++++++++++++++++----------
 4 files changed, 110 insertions(+), 26 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 3e016a6..247785e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -423,9 +423,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	char *ref = NULL;
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
+	int broken_upstream = 0;
 
-	if (!stat_tracking_info(branch, &ours, &theirs))
+	switch (stat_tracking_info(branch, &ours, &theirs)) {
+	case 0:
+		/* Not set upstream. */
 		return;
+	case -1:
+		/* Upstream is missing or invalid. */
+		broken_upstream = 1;
+		break;
+	default:
+		break;
+	}
 
 	if (show_upstream_ref) {
 		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
@@ -437,7 +447,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours && !theirs) {
+	if (broken_upstream) {
+		if (show_upstream_ref)
+			strbuf_addf(stat, _("[%s: broken]"), fancy.buf);
+	} else if (!ours && !theirs) {
 		if (show_upstream_ref)
 			strbuf_addf(stat, _("[%s]"), fancy.buf);
 	} else if (!ours) {
diff --git a/remote.c b/remote.c
index 26bd543..aa87381 100644
--- a/remote.c
+++ b/remote.c
@@ -1729,8 +1729,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 }
 
 /*
- * Return false if cannot stat a tracking branch (not exist or invalid),
- * otherwise true.
+ * Compare a branch with its tracking branch, and save their differences
+ * (number of commits) in *num_ours and *num_theirs.
+ *
+ * Return 0 if branch has no upstream, -1 if upstream is missing or invalid,
+ * otherwise 1.
  */
 int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 {
@@ -1749,16 +1752,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	/* Cannot stat if what we used to build on no longer exists */
 	base = branch->merge[0]->dst;
 	if (read_ref(base, sha1))
-		return 0;
+		return -1;
 	theirs = lookup_commit_reference(sha1);
 	if (!theirs)
-		return 0;
+		return -1;
 
 	if (read_ref(branch->refname, sha1))
-		return 0;
+		return -1;
 	ours = lookup_commit_reference(sha1);
 	if (!ours)
-		return 0;
+		return -1;
 
 	/* are we the same? */
 	if (theirs == ours) {
@@ -1808,17 +1811,33 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 {
 	int ours, theirs;
 	const char *base;
+	int broken_upstream = 0;
 
-	if (!stat_tracking_info(branch, &ours, &theirs))
-		return 0;
-
-	/* Nothing to report if neither side has changes. */
-	if (!ours && !theirs)
+	switch (stat_tracking_info(branch, &ours, &theirs)) {
+	case 0:
+		/* Not set upstream. */
 		return 0;
+	case -1:
+		/* Upstream is missing or invalid. */
+		broken_upstream = 1;
+		break;
+	default:
+		/* Nothing to report if neither side has changes. */
+		if (!ours && !theirs)
+			return 0;
+		break;
+	}
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!theirs) {
+	if (broken_upstream) {
+		strbuf_addf(sb,
+			_("Your branch is based on a broken ref '%s'.\n"),
+			base);
+		if (advice_status_hints)
+			strbuf_addf(sb,
+				_("  (use \"git branch --unset-upstream\" to fixup)\n"));
+	} else if (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 471dd64..e362a01 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -60,6 +60,7 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 brokenbase: broken
 EOF
 
 test_expect_success 'branch -vv' '
@@ -71,7 +72,7 @@ test_expect_success 'branch -vv' '
 	test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
 	(
 		cd test && git checkout b1
 	) >actual &&
@@ -84,7 +85,15 @@ test_expect_success 'checkout with local tracked branch' '
 	test_i18ngrep "is ahead of" actual
 '
 
-test_expect_success 'status' '
+test_expect_success 'checkout (broken upstream)' '
+	(
+		cd test &&
+		git checkout b5
+	) >actual &&
+	test_i18ngrep "is based on a broken ref" actual
+'
+
+test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
 		git checkout b1 >/dev/null &&
@@ -94,6 +103,42 @@ test_expect_success 'status' '
 	test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'status (broken upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		# reports nothing to commit
+		test_must_fail git commit --dry-run
+	) >actual &&
+	test_i18ngrep "is based on a broken ref" 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 [broken]
+EOF
+
+test_expect_success 'status -s -b (broken upstream)' '
+	(
+		cd test &&
+		git checkout b5 >/dev/null &&
+		git status -s -b | head -1
+	) >actual &&
+	test_i18ncmp expect actual
+'
+
 test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index 0c6a3a5..60164d4 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1363,6 +1363,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	const char *base;
 	const char *branch_name;
 	int num_ours, num_theirs;
+	int broken_upstream = 0;
 
 	color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
 
@@ -1383,17 +1384,21 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 
 	color_fprintf(s->fp, branch_color_local, "%s", branch_name);
 
-	/*
-	 * Not report tracking info if no tracking branch found
-	 * or no difference found.
-	 */
-	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
-		fputc(s->null_termination ? '\0' : '\n', s->fp);
-		return;
-	}
-	if (!num_ours && !num_theirs) {
+	switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
+	case 0:
+		/* Not report tracking info if no tracking branch found. */
 		fputc(s->null_termination ? '\0' : '\n', s->fp);
 		return;
+	case -1:
+		/* Upstream is missing or invalid. */
+		broken_upstream = 1;
+		break;
+	default:
+		if (!num_ours && !num_theirs) {
+			fputc(s->null_termination ? '\0' : '\n', s->fp);
+			return;
+		}
+		break;
 	}
 
 	base = branch->merge[0]->dst;
@@ -1402,7 +1407,9 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
 	color_fprintf(s->fp, header_color, " [");
-	if (!num_ours) {
+	if (broken_upstream) {
+		color_fprintf(s->fp, header_color, _("broken"));
+	} else if (!num_ours) {
 		color_fprintf(s->fp, header_color, _("behind "));
 		color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
 	} else if (!num_theirs) {
-- 
1.8.4.rc2.478.g12f0bfd.dirty

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v6 3/3] status: always show tracking branch even no change
  2013-08-14 15:38                 ` Junio C Hamano
  2013-08-15 18:11                   ` [PATCH v6 1/3] " Jiang Xin
  2013-08-15 18:11                   ` [PATCH v6 2/3] branch: report invalid tracking branch as broken Jiang Xin
@ 2013-08-15 18:11                   ` Jiang Xin
  2013-08-15 22:56                     ` Junio C Hamano
  2 siblings, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-15 18:11 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

In order to see what the current branch is tracking, one way is using
"git branch -v -v", but branches other than the current are also
reported. Another way is using "git status", such as:

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    ...

But this will not work if there is no change between the current
branch and its upstream. What if report upstream tracking info
always even if there is no difference. E.g.

    $ git status
    # On branch feature1
    # Your branch is identical to 'github/feature1'.
    ...

    $ git status -bs
    ## feature1...github/feature1
    ...

    $ git checkout feature1
    Already on 'feature1'
    Your branch is identical to 'github/feature1'.
    ...

Also add some test cases in t6040.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 remote.c                 |  7 ++++---
 t/t6040-tracking-info.sh | 34 +++++++++++++++++++++++++++++++++-
 wt-status.c              |  9 +++++----
 3 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/remote.c b/remote.c
index aa87381..1137394 100644
--- a/remote.c
+++ b/remote.c
@@ -1822,9 +1822,6 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 		broken_upstream = 1;
 		break;
 	default:
-		/* Nothing to report if neither side has changes. */
-		if (!ours && !theirs)
-			return 0;
 		break;
 	}
 
@@ -1837,6 +1834,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 		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 identical to '%s'.\n"),
+			base);
 	} else if (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index e362a01..404b629 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -32,7 +32,8 @@ test_expect_success setup '
 		git checkout -b brokenbase origin &&
 		git checkout -b b5 --track brokenbase &&
 		advance g &&
-		git branch -d brokenbase
+		git branch -d brokenbase &&
+		git checkout -b b6 origin
 	) &&
 	git checkout -b follower --track master &&
 	advance h
@@ -61,6 +62,7 @@ b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
 b5 brokenbase: broken
+b6 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -93,6 +95,13 @@ test_expect_success 'checkout (broken upstream)' '
 	test_i18ngrep "is based on a broken ref" actual
 '
 
+test_expect_success 'checkout (identical to upstream)' '
+	(
+		cd test && git checkout b6
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .origin/master" actual
+'
+
 test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
@@ -113,6 +122,16 @@ test_expect_success 'status (broken upstream)' '
 	test_i18ngrep "is based on a broken ref" actual
 '
 
+test_expect_success 'status (identical to 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 identical to .origin/master" actual
+'
+
 cat >expect <<\EOF
 ## b1...origin/master [ahead 1, behind 1]
 EOF
@@ -139,6 +158,19 @@ test_expect_success 'status -s -b (broken upstream)' '
 	test_i18ncmp expect actual
 '
 
+cat >expect <<\EOF
+## b6...origin/master
+EOF
+
+test_expect_success 'status -s -b (identical to 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' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index 60164d4..c66963c 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1394,10 +1394,6 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 		broken_upstream = 1;
 		break;
 	default:
-		if (!num_ours && !num_theirs) {
-			fputc(s->null_termination ? '\0' : '\n', s->fp);
-			return;
-		}
 		break;
 	}
 
@@ -1406,6 +1402,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, header_color, "...");
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
+	if (!broken_upstream && !num_ours && !num_theirs) {
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+
 	color_fprintf(s->fp, header_color, " [");
 	if (broken_upstream) {
 		color_fprintf(s->fp, header_color, _("broken"));
-- 
1.8.4.rc2.478.g12f0bfd.dirty

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v6 2/3] branch: report invalid tracking branch as broken
  2013-08-15 18:11                   ` [PATCH v6 2/3] branch: report invalid tracking branch as broken Jiang Xin
@ 2013-08-15 18:38                     ` Junio C Hamano
  2013-08-15 22:54                     ` Junio C Hamano
  1 sibling, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2013-08-15 18:38 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> If a branch has been set to track a upstream, but the upstream branch
> is missing or invalid, the tracking info is silently ignored in the
> output of some commands such as "git branch -vv" and "git status",
> as if there were no such tracking settings.
>
> Junio suggested broken upstream should be reported [1]. E.g.
>
>     $ git branch -v -v
>       master    e67ac84 initial
>     * topic     3fc0f2a [topicbase: broken] topic

I'd assume this is s/broken/gone/ to match what the rest of the log
message says?

>     $ git status
>     # On branch topic
>     # Your branch is based on a broken ref 'topicbase'.
>     #   (use "git branch --unset-upstream" to fixup)
>     ...
>
>     $ git status -b -s
>     ## topic...topicbase [broken]
>     ...
>
> 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).

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v6 2/3] branch: report invalid tracking branch as broken
  2013-08-15 18:11                   ` [PATCH v6 2/3] branch: report invalid tracking branch as broken Jiang Xin
  2013-08-15 18:38                     ` Junio C Hamano
@ 2013-08-15 22:54                     ` Junio C Hamano
  2013-08-16  2:29                       ` [PATCH v7 0/3] some enhancements for reporting branch tracking info Jiang Xin
       [not found]                       ` <cover.1376620130.git.worldhello.net@gmail.com>
  1 sibling, 2 replies; 36+ messages in thread
From: Junio C Hamano @ 2013-08-15 22:54 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

>  /*
> - * Return false if cannot stat a tracking branch (not exist or invalid),
> - * otherwise true.
> + * Compare a branch with its tracking branch, and save their differences
> + * (number of commits) in *num_ours and *num_theirs.
> + *
> + * Return 0 if branch has no upstream, -1 if upstream is missing or invalid,
> + * otherwise 1.
>   */

What is the difference between a branch that has no upstream and
upstream being missing?  Or between missing and invalid?

I think you are trying to say the difference between
"branch.<name>.merge is not set at all" and "branch.<name>.merge is
in the configuration, but the named upstream ref does not exist".

You are calling the latter "missing or invalid", but how does one
tell missing ones from invalid ones?  I think there isn't a
distinction, so it would be better to just say "missing" (or "gone",
which is very much more likely reason why you still have
configuration without a ref).

I am not sure it is a good idea to label "missing" as "broken" or
"invalid", but it seems that your tests, in code comments and
variable names are full of these negative connotations.

Hmph...

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v6 3/3] status: always show tracking branch even no change
  2013-08-15 18:11                   ` [PATCH v6 " Jiang Xin
@ 2013-08-15 22:56                     ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2013-08-15 22:56 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> In order to see what the current branch is tracking, one way is using
> "git branch -v -v", but branches other than the current are also
> reported. Another way is using "git status", such as:
>
>     $ git status
>     # On branch master
>     # Your branch is ahead of 'origin/master' by 1 commit.
>     ...
>
> But this will not work if there is no change between the current
> branch and its upstream. What if report upstream tracking info
> always even if there is no difference. E.g.
>
>     $ git status
>     # On branch feature1
>     # Your branch is identical to 'github/feature1'.
>     ...
>
>     $ git status -bs
>     ## feature1...github/feature1
>     ...
>
>     $ git checkout feature1
>     Already on 'feature1'
>     Your branch is identical to 'github/feature1'.
>     ...

The sentence that began with "What if ..." never completed?

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v7 0/3] some enhancements for reporting branch tracking info
  2013-08-15 22:54                     ` Junio C Hamano
@ 2013-08-16  2:29                       ` Jiang Xin
  2013-08-18 19:51                         ` Junio C Hamano
       [not found]                       ` <cover.1376620130.git.worldhello.net@gmail.com>
  1 sibling, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-16  2:29 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

Changes since v6:

* s/broken/gone/ in [PATCH 2/3] (branch: mark missing tracking branch
  as gone)

* rewrite commit log for [PATCH 3/3] (status: always show tracking
  branch even no change)

Jiang Xin (3):
  branch: not report invalid tracking branch
  branch: mark missing tracking branch as gone
  status: always show tracking branch even no change

 builtin/branch.c         | 36 ++++++++++++--------
 remote.c                 | 72 +++++++++++++++++++++++++--------------
 t/t6040-tracking-info.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++---
 wt-status.c              | 26 +++++++++++---
 4 files changed, 175 insertions(+), 48 deletions(-)

-- 
1.8.4.rc2.479.g44abce8

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v7 1/3] branch: not report invalid tracking branch
       [not found]                       ` <cover.1376620130.git.worldhello.net@gmail.com>
@ 2013-08-16  2:29                         ` Jiang Xin
  2013-08-16  2:29                         ` [PATCH v7 2/3] branch: mark missing tracking branch as gone Jiang Xin
  2013-08-16  2:29                         ` [PATCH v7 3/3] status: always show tracking branch even no change Jiang Xin
  2 siblings, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-16  2:29 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

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 whether the upstream branch
does not exist, or nothing is changed between one branch and its
upstream.

This patch changes the return value of function stat_tracking_info().
Only returns false when there is no tracking branch or the tracking
branch is invalid, otherwise true. 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.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/branch.c         | 24 ++++++++----------------
 remote.c                 | 43 ++++++++++++++++++++++---------------------
 t/t6040-tracking-info.sh |  8 ++++++--
 wt-status.c              | 13 +++++++++++--
 4 files changed, 47 insertions(+), 41 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0903763..3e016a6 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
 
-	if (!stat_tracking_info(branch, &ours, &theirs)) {
-		if (branch && branch->merge && branch->merge[0]->dst &&
-		    show_upstream_ref) {
-			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);
-		}
+	if (!stat_tracking_info(branch, &ours, &theirs))
 		return;
-	}
 
 	if (show_upstream_ref) {
 		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
@@ -448,19 +437,22 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours) {
-		if (ref)
+	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);
 		else
 			strbuf_addf(stat, _("[behind %d]"), theirs);
 
 	} else if (!theirs) {
-		if (ref)
+		if (show_upstream_ref)
 			strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
 		else
 			strbuf_addf(stat, _("[ahead %d]"), ours);
 	} else {
-		if (ref)
+		if (show_upstream_ref)
 			strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
 				    fancy.buf, ours, theirs);
 		else
diff --git a/remote.c b/remote.c
index 2433467..26bd543 100644
--- a/remote.c
+++ b/remote.c
@@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 }
 
 /*
- * Return true if there is anything to report, otherwise false.
+ * Return false if cannot stat a tracking branch (not exist or invalid),
+ * otherwise true.
  */
 int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 {
@@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
-	/*
-	 * Nothing to report unless we are marked to build on top of
-	 * somebody else.
-	 */
+	/* Cannot stat unless we are marked to build on top of somebody else. */
 	if (!branch ||
 	    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
 		return 0;
 
-	/*
-	 * If what we used to build on no longer exists, there is
-	 * nothing to report.
-	 */
+	/* Cannot stat if what we used to build on no longer exists */
 	base = branch->merge[0]->dst;
 	if (read_ref(base, sha1))
 		return 0;
@@ -1766,8 +1761,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 		return 0;
 
 	/* are we the same? */
-	if (theirs == ours)
-		return 0;
+	if (theirs == ours) {
+		*num_theirs = *num_ours = 0;
+		return 1;
+	}
 
 	/* Run "rev-list --left-right ours...theirs" internally... */
 	rev_argc = 0;
@@ -1809,31 +1806,35 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
  */
 int format_tracking_info(struct branch *branch, struct strbuf *sb)
 {
-	int num_ours, num_theirs;
+	int ours, theirs;
 	const char *base;
 
-	if (!stat_tracking_info(branch, &num_ours, &num_theirs))
+	if (!stat_tracking_info(branch, &ours, &theirs))
+		return 0;
+
+	/* Nothing to report if neither side has changes. */
+	if (!ours && !theirs)
 		return 0;
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!num_theirs) {
+	if (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
-			   num_ours),
-			base, num_ours);
+			   ours),
+			base, ours);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git push\" to publish your local commits)\n"));
-	} else if (!num_ours) {
+	} else if (!ours) {
 		strbuf_addf(sb,
 			Q_("Your branch is behind '%s' by %d commit, "
 			       "and can be fast-forwarded.\n",
 			   "Your branch is behind '%s' by %d commits, "
 			       "and can be fast-forwarded.\n",
-			   num_theirs),
-			base, num_theirs);
+			   theirs),
+			base, theirs);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git pull\" to update your local branch)\n"));
@@ -1845,8 +1846,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 			   "Your branch and '%s' have diverged,\n"
 			       "and have %d and %d different commits each, "
 			       "respectively.\n",
-			   num_theirs),
-			base, num_ours, num_theirs);
+			   theirs),
+			base, ours, theirs);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git pull\" to merge the remote branch into yours)\n"));
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ec2b516..471dd64 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -28,10 +28,14 @@ test_expect_success setup '
 		git reset --hard HEAD^ &&
 		git checkout -b b4 origin &&
 		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 follower --track master &&
-	advance g
+	advance h
 '
 
 script='s/^..\(b.\)[	 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
diff --git a/wt-status.c b/wt-status.c
index ff4b324..0c6a3a5 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	branch = branch_get(s->branch + 11);
 	if (s->is_initial)
 		color_fprintf(s->fp, header_color, _("Initial commit on "));
+
+	color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+
+	/*
+	 * Not report tracking info if no tracking branch found
+	 * or no difference found.
+	 */
 	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
-		color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+		fputc(s->null_termination ? '\0' : '\n', s->fp);
+		return;
+	}
+	if (!num_ours && !num_theirs) {
 		fputc(s->null_termination ? '\0' : '\n', s->fp);
 		return;
 	}
 
 	base = branch->merge[0]->dst;
 	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, branch_color_remote, "%s", base);
 
-- 
1.8.4.rc2.479.g44abce8

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v7 2/3] branch: mark missing tracking branch as gone
       [not found]                       ` <cover.1376620130.git.worldhello.net@gmail.com>
  2013-08-16  2:29                         ` [PATCH v7 1/3] branch: not report invalid tracking branch Jiang Xin
@ 2013-08-16  2:29                         ` Jiang Xin
  2013-08-21  7:37                           ` Matthieu Moy
  2013-08-16  2:29                         ` [PATCH v7 3/3] status: always show tracking branch even no change Jiang Xin
  2 siblings, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-16  2:29 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

If a branch has been set to track a upstream, but the upstream branch
is missing, the tracking info is silently ignored in the output of
some commands such as "git branch -vv" and "git status", as if there
were no such tracking settings.

Junio suggested missing upstream should be reported [1], such as:

    $ 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).

[1]: http://thread.gmane.org/gmane.comp.version-control.git/231830/focus=232288

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/branch.c         | 18 ++++++++++++++++--
 remote.c                 | 44 +++++++++++++++++++++++++++++++------------
 t/t6040-tracking-info.sh | 49 ++++++++++++++++++++++++++++++++++++++++++++++--
 wt-status.c              | 28 +++++++++++++++++----------
 4 files changed, 113 insertions(+), 26 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 3e016a6..ad0f86d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -423,9 +423,20 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	char *ref = NULL;
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
+	int upstream_is_gone = 0;
 
-	if (!stat_tracking_info(branch, &ours, &theirs))
+	switch (stat_tracking_info(branch, &ours, &theirs)) {
+	case 0:
+		/* no base */
 		return;
+	case -1:
+		/* with "gone" base */
+		upstream_is_gone = 1;
+		break;
+	default:
+		/* with base */
+		break;
+	}
 
 	if (show_upstream_ref) {
 		ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
@@ -437,7 +448,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours && !theirs) {
+	if (upstream_is_gone) {
+		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) {
diff --git a/remote.c b/remote.c
index 26bd543..4caccb5 100644
--- a/remote.c
+++ b/remote.c
@@ -1729,8 +1729,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 }
 
 /*
- * Return false if cannot stat a tracking branch (not exist or invalid),
- * otherwise true.
+ * 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)
 {
@@ -1749,16 +1752,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	/* Cannot stat if what we used to build on no longer exists */
 	base = branch->merge[0]->dst;
 	if (read_ref(base, sha1))
-		return 0;
+		return -1;
 	theirs = lookup_commit_reference(sha1);
 	if (!theirs)
-		return 0;
+		return -1;
 
 	if (read_ref(branch->refname, sha1))
-		return 0;
+		return -1;
 	ours = lookup_commit_reference(sha1);
 	if (!ours)
-		return 0;
+		return -1;
 
 	/* are we the same? */
 	if (theirs == ours) {
@@ -1808,17 +1811,34 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 {
 	int ours, theirs;
 	const char *base;
+	int upstream_is_gone = 0;
 
-	if (!stat_tracking_info(branch, &ours, &theirs))
-		return 0;
-
-	/* Nothing to report if neither side has changes. */
-	if (!ours && !theirs)
+	switch (stat_tracking_info(branch, &ours, &theirs)) {
+	case 0:
+		/* no base */
 		return 0;
+	case -1:
+		/* with "gone" base */
+		upstream_is_gone = 1;
+		break;
+	default:
+		/* Nothing to report if neither side has changes. */
+		if (!ours && !theirs)
+			return 0;
+		/* with base */
+		break;
+	}
 
 	base = branch->merge[0]->dst;
 	base = shorten_unambiguous_ref(base, 0);
-	if (!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 (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 471dd64..6f678a4 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -60,6 +60,7 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 brokenbase: gone
 EOF
 
 test_expect_success 'branch -vv' '
@@ -71,7 +72,7 @@ test_expect_success 'branch -vv' '
 	test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
 	(
 		cd test && git checkout b1
 	) >actual &&
@@ -84,7 +85,15 @@ test_expect_success 'checkout with local tracked branch' '
 	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 'status (diverged from upstream)' '
 	(
 		cd test &&
 		git checkout b1 >/dev/null &&
@@ -94,6 +103,42 @@ test_expect_success 'status' '
 	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
+'
+
+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
+'
+
 test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index 0c6a3a5..46d181a 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1363,6 +1363,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	const char *base;
 	const char *branch_name;
 	int num_ours, num_theirs;
+	int upstream_is_gone = 0;
 
 	color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
 
@@ -1383,17 +1384,22 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 
 	color_fprintf(s->fp, branch_color_local, "%s", branch_name);
 
-	/*
-	 * Not report tracking info if no tracking branch found
-	 * or no difference found.
-	 */
-	if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
-		fputc(s->null_termination ? '\0' : '\n', s->fp);
-		return;
-	}
-	if (!num_ours && !num_theirs) {
+	switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
+	case 0:
+		/* no base */
 		fputc(s->null_termination ? '\0' : '\n', s->fp);
 		return;
+	case -1:
+		/* with "gone" base */
+		upstream_is_gone = 1;
+		break;
+	default:
+		/* with base */
+		if (!num_ours && !num_theirs) {
+			fputc(s->null_termination ? '\0' : '\n', s->fp);
+			return;
+		}
+		break;
 	}
 
 	base = branch->merge[0]->dst;
@@ -1402,7 +1408,9 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, branch_color_remote, "%s", base);
 
 	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, branch_color_remote, "%d", num_theirs);
 	} else if (!num_theirs) {
-- 
1.8.4.rc2.479.g44abce8

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v7 3/3] status: always show tracking branch even no change
       [not found]                       ` <cover.1376620130.git.worldhello.net@gmail.com>
  2013-08-16  2:29                         ` [PATCH v7 1/3] branch: not report invalid tracking branch Jiang Xin
  2013-08-16  2:29                         ` [PATCH v7 2/3] branch: mark missing tracking branch as gone Jiang Xin
@ 2013-08-16  2:29                         ` Jiang Xin
  2 siblings, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-16  2:29 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

In order to see what the current branch is tracking, one way is using
"git branch -v -v", but branches other than the current are also
reported. Another way is using "git status", such as:

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    ...

But this will not work if there is no change between the current
branch and its upstream. Always report upstream tracking info
even if there is no difference, so that "git status" is consistent
for checking tracking info for current branch. E.g.

    $ git status
    # On branch feature1
    # Your branch is identical to 'github/feature1'.
    ...

    $ git status -bs
    ## feature1...github/feature1
    ...

    $ git checkout feature1
    Already on 'feature1'
    Your branch is identical to 'github/feature1'.
    ...

Also add some test cases in t6040.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 remote.c                 |  7 ++++---
 t/t6040-tracking-info.sh | 34 +++++++++++++++++++++++++++++++++-
 wt-status.c              |  9 +++++----
 3 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/remote.c b/remote.c
index 4caccb5..79effe6 100644
--- a/remote.c
+++ b/remote.c
@@ -1822,9 +1822,6 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 		upstream_is_gone = 1;
 		break;
 	default:
-		/* Nothing to report if neither side has changes. */
-		if (!ours && !theirs)
-			return 0;
 		/* with base */
 		break;
 	}
@@ -1838,6 +1835,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 		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 identical to '%s'.\n"),
+			base);
 	} else if (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 6f678a4..b24a18c 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -32,7 +32,8 @@ test_expect_success setup '
 		git checkout -b brokenbase origin &&
 		git checkout -b b5 --track brokenbase &&
 		advance g &&
-		git branch -d brokenbase
+		git branch -d brokenbase &&
+		git checkout -b b6 origin
 	) &&
 	git checkout -b follower --track master &&
 	advance h
@@ -61,6 +62,7 @@ b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
 b5 brokenbase: gone
+b6 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -93,6 +95,13 @@ test_expect_success 'checkout (upstream is gone)' '
 	test_i18ngrep "is based on .*, but the upstream is gone." actual
 '
 
+test_expect_success 'checkout (identical to upstream)' '
+	(
+		cd test && git checkout b6
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .origin/master" actual
+'
+
 test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
@@ -113,6 +122,16 @@ test_expect_success 'status (upstream is gone)' '
 	test_i18ngrep "is based on .*, but the upstream is gone." actual
 '
 
+test_expect_success 'status (identical to 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 identical to .origin/master" actual
+'
+
 cat >expect <<\EOF
 ## b1...origin/master [ahead 1, behind 1]
 EOF
@@ -139,6 +158,19 @@ test_expect_success 'status -s -b (upstream is gone)' '
 	test_i18ncmp expect actual
 '
 
+cat >expect <<\EOF
+## b6...origin/master
+EOF
+
+test_expect_success 'status -s -b (identical to 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' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index 46d181a..c8c2d77 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1395,10 +1395,6 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 		break;
 	default:
 		/* with base */
-		if (!num_ours && !num_theirs) {
-			fputc(s->null_termination ? '\0' : '\n', s->fp);
-			return;
-		}
 		break;
 	}
 
@@ -1407,6 +1403,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, header_color, "...");
 	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, " [");
 	if (upstream_is_gone) {
 		color_fprintf(s->fp, header_color, _("gone"));
-- 
1.8.4.rc2.479.g44abce8

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v7 0/3] some enhancements for reporting branch tracking info
  2013-08-16  2:29                       ` [PATCH v7 0/3] some enhancements for reporting branch tracking info Jiang Xin
@ 2013-08-18 19:51                         ` Junio C Hamano
  2013-08-19  0:38                           ` Jiang Xin
                                             ` (3 more replies)
  0 siblings, 4 replies; 36+ messages in thread
From: Junio C Hamano @ 2013-08-18 19:51 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> Changes since v6:
>
> * s/broken/gone/ in [PATCH 2/3] (branch: mark missing tracking branch
>   as gone)
>
> * rewrite commit log for [PATCH 3/3] (status: always show tracking
>   branch even no change)
>
> Jiang Xin (3):
>   branch: not report invalid tracking branch
>   branch: mark missing tracking branch as gone
>   status: always show tracking branch even no change
>
>  builtin/branch.c         | 36 ++++++++++++--------
>  remote.c                 | 72 +++++++++++++++++++++++++--------------
>  t/t6040-tracking-info.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++---
>  wt-status.c              | 26 +++++++++++---
>  4 files changed, 175 insertions(+), 48 deletions(-)

Thanks; getting clearer to read.

I however feel that [1/3] is introducing a regression (what we used
to report, gone branches, are hidden), only to correct the
regression immediately after it with [2/3].

I wonder if these patches should be combined into one, with
justification like "with the current code, a branch that is in sync
with its upstream, a branch whose upstream no longer exists and a
branch that does not build on anything else cannot be distinguished;
show the first class as 'same', mark the second class as 'gone', and
show only the last one as not having any uptream', or something.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v7 0/3] some enhancements for reporting branch tracking info
  2013-08-18 19:51                         ` Junio C Hamano
@ 2013-08-19  0:38                           ` Jiang Xin
  2013-08-26  7:02                           ` [PATCH v8 0/2] " Jiang Xin
                                             ` (2 subsequent siblings)
  3 siblings, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-19  0:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Matthieu Moy, Git List

2013/8/19 Junio C Hamano <gitster@pobox.com>:
>
> I however feel that [1/3] is introducing a regression (what we used
> to report, gone branches, are hidden), only to correct the
> regression immediately after it with [2/3].
>
> I wonder if these patches should be combined into one

Yes, at least patch 1/3 and patch 2/3 can be squashed into one.

> justification like "with the current code, a branch that is in sync
> with its upstream, a branch whose upstream no longer exists and a
> branch that does not build on anything else cannot be distinguished;
> show the first class as 'same', mark the second class as 'gone', and

For the first class, if there are differences between branch and
its upstream, tracking info is displayed, but report nothing if they
are identical. I do think report something in this case is useful.
It may help me to find out which remote I am tracking, if there are
several remotes for my repo.

> show only the last one as 'not having any uptream', or something.

I think keep silence in this case is better.

-- 
Jiang Xin

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v7 2/3] branch: mark missing tracking branch as gone
  2013-08-16  2:29                         ` [PATCH v7 2/3] branch: mark missing tracking branch as gone Jiang Xin
@ 2013-08-21  7:37                           ` Matthieu Moy
  2013-08-22  0:00                             ` Jiang Xin
  0 siblings, 1 reply; 36+ messages in thread
From: Matthieu Moy @ 2013-08-21  7:37 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Junio C Hamano, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

>     $ git status
>     # On branch topic
>     # Your branch is based on 'topicbase', but the upstream is gone.
>     #   (use "git branch --unset-upstream" to fixup)

Sorry, I didn't follow closely the previous discussions. I'm not sure
"gone" is right either, since the user may just have configured an
upstream that does not exist and never existed. Perhaps "absent" would
be better.

Just a thought, shouldn't block the patch.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v7 2/3] branch: mark missing tracking branch as gone
  2013-08-21  7:37                           ` Matthieu Moy
@ 2013-08-22  0:00                             ` Jiang Xin
  0 siblings, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-22  0:00 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Junio C Hamano, Git List

2013/8/21 Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>:
> Jiang Xin <worldhello.net@gmail.com> writes:
>
>>     $ git status
>>     # On branch topic
>>     # Your branch is based on 'topicbase', but the upstream is gone.
>>     #   (use "git branch --unset-upstream" to fixup)
>
> Sorry, I didn't follow closely the previous discussions. I'm not sure
> "gone" is right either, since the user may just have configured an
> upstream that does not exist and never existed. Perhaps "absent" would
> be better.
>
> Just a thought, shouldn't block the patch.

Thank you for following this, and offering better statements. I will
make another reroll after the end of my business trip this week.

-- 
Jiang Xin

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v8 0/2] some enhancements for reporting branch tracking info
  2013-08-18 19:51                         ` Junio C Hamano
  2013-08-19  0:38                           ` Jiang Xin
@ 2013-08-26  7:02                           ` Jiang Xin
  2013-08-26  7:21                             ` Junio C Hamano
  2013-08-26  7:02                           ` [PATCH v8 1/2] branch: report invalid tracking branch as gone Jiang Xin
  2013-08-26  7:02                           ` [PATCH v8 2/2] status: always show tracking branch even no change Jiang Xin
  3 siblings, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-26  7:02 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

Changes since v7:

* Squashed patch 1/3 and patch 2/3 into one big patch.

But not s/gone/absent/ as Matthieu suggested.

Jiang Xin (2):
  branch: report invalid tracking branch as gone
  status: always show tracking branch even no change

 builtin/branch.c         | 36 ++++++++++++--------
 remote.c                 | 72 +++++++++++++++++++++++++--------------
 t/t6040-tracking-info.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++---
 wt-status.c              | 26 +++++++++++---
 4 files changed, 175 insertions(+), 48 deletions(-)

-- 
1.8.4.rc3.2.g434fd97

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v8 1/2] branch: report invalid tracking branch as gone
  2013-08-18 19:51                         ` Junio C Hamano
  2013-08-19  0:38                           ` Jiang Xin
  2013-08-26  7:02                           ` [PATCH v8 0/2] " Jiang Xin
@ 2013-08-26  7:02                           ` Jiang Xin
  2013-08-26  7:02                           ` [PATCH v8 2/2] status: always show tracking branch even no change Jiang Xin
  3 siblings, 0 replies; 36+ messages in thread
From: Jiang Xin @ 2013-08-26  7:02 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

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 <gitster@pobox.com>
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/branch.c         | 36 ++++++++++++++----------
 remote.c                 | 71 +++++++++++++++++++++++++++++++-----------------
 t/t6040-tracking-info.sh | 57 +++++++++++++++++++++++++++++++++++---
 wt-status.c              | 26 +++++++++++++++---
 4 files changed, 142 insertions(+), 48 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0836890..0539fda 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -423,19 +423,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 	char *ref = NULL;
 	struct branch *branch = branch_get(branch_name);
 	struct strbuf fancy = STRBUF_INIT;
+	int upstream_is_gone = 0;
 
-	if (!stat_tracking_info(branch, &ours, &theirs)) {
-		if (branch && branch->merge && branch->merge[0]->dst &&
-		    show_upstream_ref) {
-			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);
-		}
+	switch (stat_tracking_info(branch, &ours, &theirs)) {
+	case 0:
+		/* no base */
 		return;
+	case -1:
+		/* with "gone" base */
+		upstream_is_gone = 1;
+		break;
+	default:
+		/* with base */
+		break;
 	}
 
 	if (show_upstream_ref) {
@@ -448,19 +448,25 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
 			strbuf_addstr(&fancy, ref);
 	}
 
-	if (!ours) {
-		if (ref)
+	if (upstream_is_gone) {
+		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);
 		else
 			strbuf_addf(stat, _("[behind %d]"), theirs);
 
 	} else if (!theirs) {
-		if (ref)
+		if (show_upstream_ref)
 			strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
 		else
 			strbuf_addf(stat, _("[ahead %d]"), ours);
 	} else {
-		if (ref)
+		if (show_upstream_ref)
 			strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
 				    fancy.buf, ours, theirs);
 		else
diff --git a/remote.c b/remote.c
index efcba93..87c8dd3 100644
--- a/remote.c
+++ b/remote.c
@@ -1695,7 +1695,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)
 {
@@ -1706,34 +1710,30 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 	const char *rev_argv[10], *base;
 	int rev_argc;
 
-	/*
-	 * Nothing to report unless we are marked to build on top of
-	 * somebody else.
-	 */
+	/* Cannot stat unless we are marked to build on top of somebody else. */
 	if (!branch ||
 	    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
 		return 0;
 
-	/*
-	 * If what we used to build on no longer exists, there is
-	 * nothing to report.
-	 */
+	/* Cannot stat if what we used to build on no longer exists */
 	base = branch->merge[0]->dst;
 	if (read_ref(base, sha1))
-		return 0;
+		return -1;
 	theirs = lookup_commit_reference(sha1);
 	if (!theirs)
-		return 0;
+		return -1;
 
 	if (read_ref(branch->refname, sha1))
-		return 0;
+		return -1;
 	ours = lookup_commit_reference(sha1);
 	if (!ours)
-		return 0;
+		return -1;
 
 	/* are we the same? */
-	if (theirs == ours)
-		return 0;
+	if (theirs == ours) {
+		*num_theirs = *num_ours = 0;
+		return 1;
+	}
 
 	/* Run "rev-list --left-right ours...theirs" internally... */
 	rev_argc = 0;
@@ -1775,31 +1775,52 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
  */
 int format_tracking_info(struct branch *branch, struct strbuf *sb)
 {
-	int num_ours, num_theirs;
+	int ours, theirs;
 	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;
+	case -1:
+		/* with "gone" base */
+		upstream_is_gone = 1;
+		break;
+	default:
+		/* Nothing to report if neither side has changes. */
+		if (!ours && !theirs)
+			return 0;
+		/* with base */
+		break;
+	}
 
 	base = branch->merge[0]->dst;
 	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 (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
 			   "Your branch is ahead of '%s' by %d commits.\n",
-			   num_ours),
-			base, num_ours);
+			   ours),
+			base, ours);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git push\" to publish your local commits)\n"));
-	} else if (!num_ours) {
+	} else if (!ours) {
 		strbuf_addf(sb,
 			Q_("Your branch is behind '%s' by %d commit, "
 			       "and can be fast-forwarded.\n",
 			   "Your branch is behind '%s' by %d commits, "
 			       "and can be fast-forwarded.\n",
-			   num_theirs),
-			base, num_theirs);
+			   theirs),
+			base, theirs);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git pull\" to update your local branch)\n"));
@@ -1811,8 +1832,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 			   "Your branch and '%s' have diverged,\n"
 			       "and have %d and %d different commits each, "
 			       "respectively.\n",
-			   num_theirs),
-			base, num_ours, num_theirs);
+			   theirs),
+			base, ours, theirs);
 		if (advice_status_hints)
 			strbuf_addf(sb,
 				_("  (use \"git pull\" to merge the remote branch into yours)\n"));
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index ec2b516..6f678a4 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -28,10 +28,14 @@ test_expect_success setup '
 		git reset --hard HEAD^ &&
 		git checkout -b b4 origin &&
 		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 follower --track master &&
-	advance g
+	advance h
 '
 
 script='s/^..\(b.\)[	 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
@@ -56,6 +60,7 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 brokenbase: gone
 EOF
 
 test_expect_success 'branch -vv' '
@@ -67,7 +72,7 @@ test_expect_success 'branch -vv' '
 	test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
 	(
 		cd test && git checkout b1
 	) >actual &&
@@ -80,7 +85,15 @@ test_expect_success 'checkout with local tracked branch' '
 	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 'status (diverged from upstream)' '
 	(
 		cd test &&
 		git checkout b1 >/dev/null &&
@@ -90,6 +103,42 @@ test_expect_success 'status' '
 	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
+'
+
+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
+'
+
 test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index cb24f1f..4b1713e 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1365,6 +1365,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	const char *base;
 	const char *branch_name;
 	int num_ours, num_theirs;
+	int upstream_is_gone = 0;
 
 	color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
 
@@ -1382,20 +1383,37 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	branch = branch_get(s->branch + 11);
 	if (s->is_initial)
 		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);
 		return;
+	case -1:
+		/* with "gone" base */
+		upstream_is_gone = 1;
+		break;
+	default:
+		/* Stop reporting if neither side has changes. */
+		if (!num_ours && !num_theirs) {
+			fputc(s->null_termination ? '\0' : '\n', s->fp);
+			return;
+		}
+		/* with base */
+		break;
 	}
 
 	base = branch->merge[0]->dst;
 	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, branch_color_remote, "%s", base);
 
 	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, branch_color_remote, "%d", num_theirs);
 	} else if (!num_theirs) {
-- 
1.8.4.rc3.2.g434fd97

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v8 2/2] status: always show tracking branch even no change
  2013-08-18 19:51                         ` Junio C Hamano
                                             ` (2 preceding siblings ...)
  2013-08-26  7:02                           ` [PATCH v8 1/2] branch: report invalid tracking branch as gone Jiang Xin
@ 2013-08-26  7:02                           ` Jiang Xin
  2013-08-26  7:47                             ` Jeremy Rosen
  3 siblings, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-26  7:02 UTC (permalink / raw)
  To: Junio C Hamano, Matthieu Moy; +Cc: Git List, Jiang Xin

In order to see what the current branch is tracking, one way is using
"git branch -v -v", but branches other than the current are also
reported. Another way is using "git status", such as:

    $ git status
    # On branch master
    # Your branch is ahead of 'origin/master' by 1 commit.
    ...

But this will not work if there is no change between the current
branch and its upstream. Always report upstream tracking info
even if there is no difference, so that "git status" is consistent
for checking tracking info for current branch. E.g.

    $ git status
    # On branch feature1
    # Your branch is identical to 'github/feature1'.
    ...

    $ git status -bs
    ## feature1...github/feature1
    ...

    $ git checkout feature1
    Already on 'feature1'
    Your branch is identical to 'github/feature1'.
    ...

Also add some test cases in t6040.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 remote.c                 |  7 ++++---
 t/t6040-tracking-info.sh | 34 +++++++++++++++++++++++++++++++++-
 wt-status.c              | 10 +++++-----
 3 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/remote.c b/remote.c
index 87c8dd3..7a8fe3f 100644
--- a/remote.c
+++ b/remote.c
@@ -1788,9 +1788,6 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 		upstream_is_gone = 1;
 		break;
 	default:
-		/* Nothing to report if neither side has changes. */
-		if (!ours && !theirs)
-			return 0;
 		/* with base */
 		break;
 	}
@@ -1804,6 +1801,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
 		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 identical to '%s'.\n"),
+			base);
 	} else if (!theirs) {
 		strbuf_addf(sb,
 			Q_("Your branch is ahead of '%s' by %d commit.\n",
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 6f678a4..b24a18c 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -32,7 +32,8 @@ test_expect_success setup '
 		git checkout -b brokenbase origin &&
 		git checkout -b b5 --track brokenbase &&
 		advance g &&
-		git branch -d brokenbase
+		git branch -d brokenbase &&
+		git checkout -b b6 origin
 	) &&
 	git checkout -b follower --track master &&
 	advance h
@@ -61,6 +62,7 @@ b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
 b5 brokenbase: gone
+b6 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -93,6 +95,13 @@ test_expect_success 'checkout (upstream is gone)' '
 	test_i18ngrep "is based on .*, but the upstream is gone." actual
 '
 
+test_expect_success 'checkout (identical to upstream)' '
+	(
+		cd test && git checkout b6
+	) >actual &&
+	test_i18ngrep "Your branch is identical to .origin/master" actual
+'
+
 test_expect_success 'status (diverged from upstream)' '
 	(
 		cd test &&
@@ -113,6 +122,16 @@ test_expect_success 'status (upstream is gone)' '
 	test_i18ngrep "is based on .*, but the upstream is gone." actual
 '
 
+test_expect_success 'status (identical to 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 identical to .origin/master" actual
+'
+
 cat >expect <<\EOF
 ## b1...origin/master [ahead 1, behind 1]
 EOF
@@ -139,6 +158,19 @@ test_expect_success 'status -s -b (upstream is gone)' '
 	test_i18ncmp expect actual
 '
 
+cat >expect <<\EOF
+## b6...origin/master
+EOF
+
+test_expect_success 'status -s -b (identical to 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' '
 	git checkout master &&
 	git tag light &&
diff --git a/wt-status.c b/wt-status.c
index 4b1713e..c5e6817 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1396,11 +1396,6 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 		upstream_is_gone = 1;
 		break;
 	default:
-		/* Stop reporting if neither side has changes. */
-		if (!num_ours && !num_theirs) {
-			fputc(s->null_termination ? '\0' : '\n', s->fp);
-			return;
-		}
 		/* with base */
 		break;
 	}
@@ -1410,6 +1405,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
 	color_fprintf(s->fp, header_color, "...");
 	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, " [");
 	if (upstream_is_gone) {
 		color_fprintf(s->fp, header_color, _("gone"));
-- 
1.8.4.rc3.2.g434fd97

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v8 0/2] some enhancements for reporting branch tracking info
  2013-08-26  7:02                           ` [PATCH v8 0/2] " Jiang Xin
@ 2013-08-26  7:21                             ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2013-08-26  7:21 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Matthieu Moy, Git List

Jiang Xin <worldhello.net@gmail.com> writes:

> Changes since v7:
>
> * Squashed patch 1/3 and patch 2/3 into one big patch.
>
> But not s/gone/absent/ as Matthieu suggested.

Thanks. Will requeue.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v8 2/2] status: always show tracking branch even no change
  2013-08-26  7:02                           ` [PATCH v8 2/2] status: always show tracking branch even no change Jiang Xin
@ 2013-08-26  7:47                             ` Jeremy Rosen
  2013-08-26  8:04                               ` Jiang Xin
  0 siblings, 1 reply; 36+ messages in thread
From: Jeremy Rosen @ 2013-08-26  7:47 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Git List, Junio C Hamano, Matthieu Moy

> 
> But this will not work if there is no change between the current
> branch and its upstream. Always report upstream tracking info
> even if there is no difference, so that "git status" is consistent
> for checking tracking info for current branch. E.g.
> 
>     $ git status
>     # On branch feature1
>     # Your branch is identical to 'github/feature1'.
>     ...
> 
>     $ git status -bs
>     ## feature1...github/feature1
>     ...
> 
>     $ git checkout feature1
>     Already on 'feature1'
>     Your branch is identical to 'github/feature1'.
>     ...
> 


nitpicking, but shouldn't this be worded as "up to date" rather than "identical" ?

The reason is that identical gives the idea that the two branch happen to be on the same
commit wheras "up to date" gives the idea that there is a special relationship between
these two particular branches. We are not just listing all branches on the same
commit as us, we are actively telling you about this branch because it's interesting
to you.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v8 2/2] status: always show tracking branch even no change
  2013-08-26  7:47                             ` Jeremy Rosen
@ 2013-08-26  8:04                               ` Jiang Xin
  2013-08-26 16:08                                 ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Jiang Xin @ 2013-08-26  8:04 UTC (permalink / raw)
  To: Jeremy Rosen; +Cc: Git List, Junio C Hamano, Matthieu Moy

2013/8/26 Jeremy Rosen <jeremy.rosen@openwide.fr>:
>
> nitpicking, but shouldn't this be worded as "up to date" rather than "identical" ?
>
> The reason is that identical gives the idea that the two branch happen to be on the same
> commit wheras "up to date" gives the idea that there is a special relationship between
> these two particular branches. We are not just listing all branches on the same
> commit as us, we are actively telling you about this branch because it's interesting
> to you.

That's better. I want to use 'up to date' in the beginning, but I don't know
which prep. should be used. Now I realize I should:

    s/identical to/up to date with/

-- 
Jiang Xin

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v8 2/2] status: always show tracking branch even no change
  2013-08-26  8:04                               ` Jiang Xin
@ 2013-08-26 16:08                                 ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2013-08-26 16:08 UTC (permalink / raw)
  To: Jiang Xin; +Cc: Jeremy Rosen, Git List, Matthieu Moy

Jiang Xin <worldhello.net@gmail.com> writes:

> 2013/8/26 Jeremy Rosen <jeremy.rosen@openwide.fr>:
>>
>> nitpicking, but shouldn't this be worded as "up to date" rather than "identical" ?
>>
>> The reason is that identical gives the idea that the two branch happen to be on the same
>> commit wheras "up to date" gives the idea that there is a special relationship between
>> these two particular branches. We are not just listing all branches on the same
>> commit as us, we are actively telling you about this branch because it's interesting
>> to you.
>
> That's better. I want to use 'up to date' in the beginning, but I don't know
> which prep. should be used. Now I realize I should:
>
>     s/identical to/up to date with/

Yeah, that, or "in sync with" which may be a bit shorter.

I'll queue with "up-to-date with", as "git grep 'up to date'" tells
me that it is less common than "git grep 'up-to-date'", for now.

Thanks.

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2013-08-26 16:09 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-07 15:42 [RFC] status: show tracking branch even no difference Jiang Xin
2013-08-07 15:50 ` Matthieu Moy
2013-08-07 16:03   ` Jiang Xin
2013-08-08  5:40   ` [PATCH v2] status: always show tracking branch even no change Jiang Xin
2013-08-08 14:49     ` [PATCH v3] " Jiang Xin
2013-08-08 14:49     ` Jiang Xin
2013-08-09 21:18       ` Junio C Hamano
2013-08-10 15:05         ` Jiang Xin
2013-08-12  6:15           ` Junio C Hamano
2013-08-13  4:49             ` Jiang Xin
2013-08-13  4:53               ` [PATCH v5 1/2] branch: not report invalid tracking branch Jiang Xin
2013-08-14 15:21                 ` Junio C Hamano
2013-08-15  2:14                   ` Jiang Xin
2013-08-14 15:38                 ` Junio C Hamano
2013-08-15 18:11                   ` [PATCH v6 1/3] " Jiang Xin
2013-08-15 18:11                   ` [PATCH v6 2/3] branch: report invalid tracking branch as broken Jiang Xin
2013-08-15 18:38                     ` Junio C Hamano
2013-08-15 22:54                     ` Junio C Hamano
2013-08-16  2:29                       ` [PATCH v7 0/3] some enhancements for reporting branch tracking info Jiang Xin
2013-08-18 19:51                         ` Junio C Hamano
2013-08-19  0:38                           ` Jiang Xin
2013-08-26  7:02                           ` [PATCH v8 0/2] " Jiang Xin
2013-08-26  7:21                             ` Junio C Hamano
2013-08-26  7:02                           ` [PATCH v8 1/2] branch: report invalid tracking branch as gone Jiang Xin
2013-08-26  7:02                           ` [PATCH v8 2/2] status: always show tracking branch even no change Jiang Xin
2013-08-26  7:47                             ` Jeremy Rosen
2013-08-26  8:04                               ` Jiang Xin
2013-08-26 16:08                                 ` Junio C Hamano
     [not found]                       ` <cover.1376620130.git.worldhello.net@gmail.com>
2013-08-16  2:29                         ` [PATCH v7 1/3] branch: not report invalid tracking branch Jiang Xin
2013-08-16  2:29                         ` [PATCH v7 2/3] branch: mark missing tracking branch as gone Jiang Xin
2013-08-21  7:37                           ` Matthieu Moy
2013-08-22  0:00                             ` Jiang Xin
2013-08-16  2:29                         ` [PATCH v7 3/3] status: always show tracking branch even no change Jiang Xin
2013-08-15 18:11                   ` [PATCH v6 " Jiang Xin
2013-08-15 22:56                     ` Junio C Hamano
2013-08-13  4:53               ` [PATCH v5 2/2] " Jiang Xin

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).