{"thread":{"id":"34633","subject":"[RFC] status: show tracking branch even no difference","startedAt":"2013-08-07T15:42:01Z","lastAt":"2013-08-26T16:08:50Z","messageCount":36,"participants":["Jiang Xin","Matthieu Moy","Junio C Hamano","Jeremy Rosen"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"224755","messageId":"46fb1948a57990b0ea737401f2d60f654da4bb4f.1375890091.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":null,"subject":"[RFC] status: show tracking branch even no difference","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-07T15:42:01Z","receivedAt":"2013-08-07T15:42:01Z","isPatch":false,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"If the current branch has an upstream branch, and there are differences\nbetween the current branch and its upstream, some commands (such as\n\"git status\", \"git status -bs\", and \"git checkout\") will report their\nrelationship. E.g.\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    #   (use \"git push\" to publish your local commits)\n    #\n    ...\n\n    $ git status -bs\n    ## master...origin/master [ahead 1]\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is ahead of 'origin/master' by 1 commit.\n      (use \"git push\" to publish your local commits)\n\nBut if there is no difference between the current branch and its\nupstream, the relationship will not be reported, and it's hard to\ntell whether the current branch has a tracking branch or not. And\nwhat's worse, when the 'push.default' config variable is set to\n`matching`, it's hard to tell whether current branch is pushed out\nor not [1].\n\nWith this patch, \"git status\" will report relationship between current\nbranch and its upstream counterpart even if there is no difference.\n\n    $ git status\n    # On branch master\n    # Your branch is identical to its tracking branch: 'origin/master'.\n    #\n    ...\n\n    $ git status -bs\n    ## master...origin/master\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is identical to its tracking branch: 'origin/master'.\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/198703\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n remote.c    | 22 ++++++++++++++++------\n wt-status.c | 13 ++++++++++---\n 2 files changed, 26 insertions(+), 9 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 2433467..8d6f278 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n+\t/* Set both num_theirs and num_ours as undetermined. */\n+\t*num_theirs = -1;\n+\t*num_ours = -1;\n+\n \t/*\n \t * Nothing to report unless we are marked to build on top of\n \t * somebody else.\n@@ -1758,14 +1762,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \ttheirs = lookup_commit_reference(sha1);\n \tif (!theirs)\n \t\treturn 0;\n+\t*num_theirs = 0;\n \n \tif (read_ref(branch->refname, sha1))\n \t\treturn 0;\n \tours = lookup_commit_reference(sha1);\n \tif (!ours)\n \t\treturn 0;\n+\t*num_ours = 0;\n \n-\t/* are we the same? */\n+\t/* are we the same? both num_theirs and num_ours are set to 0. */\n \tif (theirs == ours)\n \t\treturn 0;\n \n@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tprepare_revision_walk(&revs);\n \n \t/* ... and count the commits on each side. */\n-\t*num_ours = 0;\n-\t*num_theirs = 0;\n \twhile (1) {\n \t\tstruct commit *c = get_revision(&revs);\n \t\tif (!c)\n@@ -1812,12 +1816,18 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \tint num_ours, num_theirs;\n \tconst char *base;\n \n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n-\t\treturn 0;\n+\tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n+\t\tif (num_ours || num_theirs)\n+\t\t\treturn 0;\n+\t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (!num_ours && !num_theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to its tracking branch: '%s'.\\n\"),\n+\t\t\tbase);\n+\t} else if (!num_theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\ndiff --git a/wt-status.c b/wt-status.c\nindex ff4b324..56f3c19 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1381,9 +1381,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tif (s->is_initial)\n \t\tcolor_fprintf(s->fp, header_color, _(\"Initial commit on \"));\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n-\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\treturn;\n+\t\tif (num_ours || num_theirs) {\n+\t\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\t\treturn;\n+\t\t}\n \t}\n \n \tbase = branch->merge[0]->dst;\n@@ -1392,6 +1394,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n-- \n1.8.4.rc1.429.g46fb194\n"},{"id":"224757","messageId":"vpqr4e5h55b.fsf@anie.imag.fr","threadId":"34633","inReplyTo":"46fb1948a57990b0ea737401f2d60f654da4bb4f.1375890091.git.worldhello.net@gmail.com","subject":"Re: [RFC] status: show tracking branch even no difference","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2013-08-07T15:50:08Z","receivedAt":"2013-08-07T15:50:08Z","isPatch":false,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> With this patch, \"git status\" will report relationship between current\n> branch and its upstream counterpart even if there is no difference.\n>\n>     $ git status\n>     # On branch master\n>     # Your branch is identical to its tracking branch: 'origin/master'.\n\nWhy not, but we try to say \"remote-tracking branch\" instead of just\n\"tracking\". Adding \"remote-\" in your wording may make the line a bit\nlong, but it may be sufficient to say\n\n# Your branch is identical to 'origin/master'\n\nThat's consistant with other messages like\n\n# Your branch is ahead of '%s' by %d commits\n\n(And this would deserve a test)\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"224760","messageId":"CANYiYbFaKmMpX=8FTB3LGMVvF4JUpqXo=T1zZ7+tog5aUJhzLQ@mail.gmail.com","threadId":"34633","inReplyTo":"vpqr4e5h55b.fsf@anie.imag.fr","subject":"Re: [RFC] status: show tracking branch even no difference","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-07T16:03:42Z","receivedAt":"2013-08-07T16:03:42Z","isPatch":false,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"2013/8/7 Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>:\n> Jiang Xin <worldhello.net@gmail.com> writes:\n>\n>> With this patch, \"git status\" will report relationship between current\n>> branch and its upstream counterpart even if there is no difference.\n>>\n>>     $ git status\n>>     # On branch master\n>>     # Your branch is identical to its tracking branch: 'origin/master'.\n>\n> Why not, but we try to say \"remote-tracking branch\" instead of just\n> \"tracking\". Adding \"remote-\" in your wording may make the line a bit\n> long, but it may be sufficient to say\n>\n> # Your branch is identical to 'origin/master'\n\nThat's better. Thanks.\n\n>\n> That's consistant with other messages like\n>\n> # Your branch is ahead of '%s' by %d commits\n>\n> (And this would deserve a test)\n\nWill add some test cases in t6040 if this patch has value.\n\n-- \nJiang Xin\n"},{"id":"224787","messageId":"1481cfff6c22568f2a73613668cee0b99ceb4629.1375940354.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"vpqr4e5h55b.fsf@anie.imag.fr","subject":"[PATCH v2] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-08T05:40:20Z","receivedAt":"2013-08-08T05:40:20Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"If the current branch has an upstream branch, and there are changes\nbetween the current branch and its upstream, some commands (such as\n\"git status\", \"git status -bs\", and \"git checkout\") will report their\nrelationship. E.g.\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    #   (use \"git push\" to publish your local commits)\n    #\n    ...\n\n    $ git status -bs\n    ## master...origin/master [ahead 1]\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is ahead of 'origin/master' by 1 commit.\n      (use \"git push\" to publish your local commits)\n\nBut if there is no difference between the current branch and its\nupstream, the relationship will not be reported, and it's hard to\ntell whether the current branch has a tracking branch or not. And\nwhat's worse, when the 'push.default' config variable is set to\n`matching`, it's hard to tell whether the current branch has already\nbeen pushed out or not at all [1].\n\nWith this patch, \"git status\" will report relationship between the\ncurrent branch and its upstream counterpart even if there is no\ndifference.\n\n    $ git status\n    # On branch master\n    # Your branch is identical to 'origin/master'.\n    #\n    ...\n\n    $ git status -bs\n    ## master...origin/master\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is identical to 'origin/master'.\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/198703\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n remote.c                 | 22 ++++++++++++++------\n t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----\n wt-status.c              | 13 +++++++++---\n 3 files changed, 76 insertions(+), 13 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 2433467..825f278 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n+\t/* Set both num_theirs and num_ours as undetermined. */\n+\t*num_theirs = -1;\n+\t*num_ours = -1;\n+\n \t/*\n \t * Nothing to report unless we are marked to build on top of\n \t * somebody else.\n@@ -1758,14 +1762,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \ttheirs = lookup_commit_reference(sha1);\n \tif (!theirs)\n \t\treturn 0;\n+\t*num_theirs = 0;\n \n \tif (read_ref(branch->refname, sha1))\n \t\treturn 0;\n \tours = lookup_commit_reference(sha1);\n \tif (!ours)\n \t\treturn 0;\n+\t*num_ours = 0;\n \n-\t/* are we the same? */\n+\t/* are we the same? both num_theirs and num_ours have been set to 0. */\n \tif (theirs == ours)\n \t\treturn 0;\n \n@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tprepare_revision_walk(&revs);\n \n \t/* ... and count the commits on each side. */\n-\t*num_ours = 0;\n-\t*num_theirs = 0;\n \twhile (1) {\n \t\tstruct commit *c = get_revision(&revs);\n \t\tif (!c)\n@@ -1812,12 +1816,18 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \tint num_ours, num_theirs;\n \tconst char *base;\n \n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n-\t\treturn 0;\n+\tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n+\t\tif (num_ours || num_theirs)\n+\t\t\treturn 0;\n+\t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (!num_ours && !num_theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to '%s'.\\n\"),\n+\t\t\tbase);\n+\t} else if (!num_theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..eafce7d 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -28,18 +28,20 @@ test_expect_success setup '\n \t\tgit reset --hard HEAD^ &&\n \t\tgit checkout -b b4 origin &&\n \t\tadvance e &&\n-\t\tadvance f\n+\t\tadvance f &&\n+\t\tgit checkout -b b5 origin\n \t) &&\n \tgit checkout -b follower --track master &&\n \tadvance g\n '\n \n-script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\n+script='s/^..\\(b.\\)[\t 0-9a-f]*\\(\\[\\([^]]*\\)\\]\\)\\{0,1\\}.*/\\1 \\3/p'\n cat >expect <<\\EOF\n b1 ahead 1, behind 1\n b2 ahead 1, behind 1\n b3 behind 1\n b4 ahead 2\n+b5 \n EOF\n \n test_expect_success 'branch -v' '\n@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1\n b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n+b5 origin/master\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '\n \ttest_i18ncmp expect actual\n '\n \n-test_expect_success 'checkout' '\n+test_expect_success 'checkout (diverged from upstream)' '\n \t(\n \t\tcd test && git checkout b1\n \t) >actual &&\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'checkout (identical to upstream)' '\n+\t(\n+\t\tcd test && git checkout b5\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n test_expect_success 'checkout with local tracked branch' '\n \tgit checkout master &&\n \tgit checkout follower >actual &&\n \ttest_i18ngrep \"is ahead of\" actual\n '\n \n-test_expect_success 'status' '\n+test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n \t\tgit checkout b1 >/dev/null &&\n@@ -90,6 +100,42 @@ test_expect_success 'status' '\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'status (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n+cat >expect <<\\EOF\n+## b1...origin/master [ahead 1, behind 1]\n+EOF\n+\n+test_expect_success 'status -s -b (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+## b5...origin/master\n+EOF\n+\n+test_expect_success 'status -s -b (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex ff4b324..56f3c19 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1381,9 +1381,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tif (s->is_initial)\n \t\tcolor_fprintf(s->fp, header_color, _(\"Initial commit on \"));\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n-\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\treturn;\n+\t\tif (num_ours || num_theirs) {\n+\t\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\t\treturn;\n+\t\t}\n \t}\n \n \tbase = branch->merge[0]->dst;\n@@ -1392,6 +1394,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n-- \n1.8.4.rc1.429.geed1a03\n"},{"id":"224814","messageId":"cover.1375972599.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"1481cfff6c22568f2a73613668cee0b99ceb4629.1375940354.git.worldhello.net@gmail.com","subject":"[PATCH v3] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-08T14:49:20Z","receivedAt":"2013-08-08T14:49:20Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Changes since v2:\n\n * The return value of function stat_tracking_info() is changed.\n   When the current branch and its remote tracking branch point\n   to the same commit, will return 1, instead of 0. Because we\n   want to report the tracking info for such case.\n\n * Remove duplicated codes in builtin/branch.c, and make it simpler.\n\nJiang Xin (1):\n  status: always show tracking branch even no change\n\n builtin/branch.c         | 18 +++++-----------\n remote.c                 | 18 +++++++++++-----\n t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----\n wt-status.c              |  5 +++++\n 4 files changed, 73 insertions(+), 22 deletions(-)\n\n-- \n1.8.4.rc1.430.g417e2f3\n"},{"id":"224815","messageId":"0affa278c225273a2d3fdcf8f55b61e26d322f1e.1375972599.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"cover.1375972599.git.worldhello.net@gmail.com","subject":"[PATCH v3] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-08T14:49:21Z","receivedAt":"2013-08-08T14:49:21Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"If the current branch has an upstream branch, and there are changes\nbetween the current branch and its upstream, some commands (such as\n\"git status\", \"git status -bs\", and \"git checkout\") will report their\nrelationship. E.g.\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    #   (use \"git push\" to publish your local commits)\n    #\n    ...\n\n    $ git status -bs\n    ## master...origin/master [ahead 1]\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is ahead of 'origin/master' by 1 commit.\n      (use \"git push\" to publish your local commits)\n\nBut if there is no difference between the current branch and its\nupstream, the relationship will not be reported, and it's hard to\ntell whether the current branch has a tracking branch or not. And\nwhat's worse, when the 'push.default' config variable is set to\n`matching`, it's hard to tell whether the current branch has already\nbeen pushed out or not at all [1].\n\nSo always show the remote tracking branch in the output of \"git status\"\nand other commands will help users to see where the current branch\nwill push to and pull from. E.g.\n\n    $ git status\n    # On branch master\n    # Your branch is identical to 'origin/master'.\n    #\n    ...\n\n    $ git status -bs\n    ## master...origin/master\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is identical to 'origin/master'.\n\nThis patch changes the return value of function stat_tracking_info().\nWhen the current branch and its remote tracking branch point to the\nsame commit, will return 1, instead of 0. Because we want to report\nthe tracking info for such case. Also add some test cases in t6040.\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/198703\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/branch.c         | 18 +++++-----------\n remote.c                 | 18 +++++++++++-----\n t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----\n wt-status.c              |  5 +++++\n 4 files changed, 73 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0836890..359e75d 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n-\t\t    show_upstream_ref) {\n-\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\t\tif (want_color(branch_use_color))\n-\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\t\telse\n-\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n-\t\t}\n+\tif (!stat_tracking_info(branch, &ours, &theirs))\n \t\treturn;\n-\t}\n \n \tif (show_upstream_ref) {\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n@@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours) {\n+\tif (!ours && !theirs) {\n+\t\tif (ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n+\t} else if (!ours) {\n \t\tif (ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n \t\telse\ndiff --git a/remote.c b/remote.c\nindex 2433467..79766df 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n+\t/* Set both num_theirs and num_ours as undetermined. */\n+\t*num_theirs = -1;\n+\t*num_ours = -1;\n+\n \t/*\n \t * Nothing to report unless we are marked to build on top of\n \t * somebody else.\n@@ -1758,16 +1762,18 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \ttheirs = lookup_commit_reference(sha1);\n \tif (!theirs)\n \t\treturn 0;\n+\t*num_theirs = 0;\n \n \tif (read_ref(branch->refname, sha1))\n \t\treturn 0;\n \tours = lookup_commit_reference(sha1);\n \tif (!ours)\n \t\treturn 0;\n+\t*num_ours = 0;\n \n-\t/* are we the same? */\n+\t/* are we the same? both num_theirs and num_ours have been set to 0. */\n \tif (theirs == ours)\n-\t\treturn 0;\n+\t\treturn 1;\n \n \t/* Run \"rev-list --left-right ours...theirs\" internally... */\n \trev_argc = 0;\n@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tprepare_revision_walk(&revs);\n \n \t/* ... and count the commits on each side. */\n-\t*num_ours = 0;\n-\t*num_theirs = 0;\n \twhile (1) {\n \t\tstruct commit *c = get_revision(&revs);\n \t\tif (!c)\n@@ -1817,7 +1821,11 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (!num_ours && !num_theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to '%s'.\\n\"),\n+\t\t\tbase);\n+\t} else if (!num_theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..eafce7d 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -28,18 +28,20 @@ test_expect_success setup '\n \t\tgit reset --hard HEAD^ &&\n \t\tgit checkout -b b4 origin &&\n \t\tadvance e &&\n-\t\tadvance f\n+\t\tadvance f &&\n+\t\tgit checkout -b b5 origin\n \t) &&\n \tgit checkout -b follower --track master &&\n \tadvance g\n '\n \n-script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\n+script='s/^..\\(b.\\)[\t 0-9a-f]*\\(\\[\\([^]]*\\)\\]\\)\\{0,1\\}.*/\\1 \\3/p'\n cat >expect <<\\EOF\n b1 ahead 1, behind 1\n b2 ahead 1, behind 1\n b3 behind 1\n b4 ahead 2\n+b5 \n EOF\n \n test_expect_success 'branch -v' '\n@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1\n b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n+b5 origin/master\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '\n \ttest_i18ncmp expect actual\n '\n \n-test_expect_success 'checkout' '\n+test_expect_success 'checkout (diverged from upstream)' '\n \t(\n \t\tcd test && git checkout b1\n \t) >actual &&\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'checkout (identical to upstream)' '\n+\t(\n+\t\tcd test && git checkout b5\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n test_expect_success 'checkout with local tracked branch' '\n \tgit checkout master &&\n \tgit checkout follower >actual &&\n \ttest_i18ngrep \"is ahead of\" actual\n '\n \n-test_expect_success 'status' '\n+test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n \t\tgit checkout b1 >/dev/null &&\n@@ -90,6 +100,42 @@ test_expect_success 'status' '\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'status (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n+cat >expect <<\\EOF\n+## b1...origin/master [ahead 1, behind 1]\n+EOF\n+\n+test_expect_success 'status -s -b (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+## b5...origin/master\n+EOF\n+\n+test_expect_success 'status -s -b (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex ff4b324..39742ff 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1392,6 +1392,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n-- \n1.8.4.rc1.430.g417e2f3\n"},{"id":"224953","messageId":"7vob964l6v.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"0affa278c225273a2d3fdcf8f55b61e26d322f1e.1375972599.git.worldhello.net@gmail.com","subject":"Re: [PATCH v3] status: always show tracking branch even no change","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-09T21:18:48Z","receivedAt":"2013-08-09T21:18:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> If the current branch has an upstream branch, and there are changes\n> between the current branch and its upstream, some commands (such as\n> \"git status\", \"git status -bs\", and \"git checkout\") will report their\n> relationship. E.g.\n>\n>     $ git status\n>     # On branch master\n>     # Your branch is ahead of 'origin/master' by 1 commit.\n>     #   (use \"git push\" to publish your local commits)\n>     #\n>     ...\n>\n>     $ git status -bs\n>     ## master...origin/master [ahead 1]\n>     ...\n>\n>     $ git checkout master\n>     Already on 'master'\n>     Your branch is ahead of 'origin/master' by 1 commit.\n>       (use \"git push\" to publish your local commits)\n>\n> But if there is no difference between the current branch and its\n> upstream, the relationship will not be reported, and it's hard to\n> tell whether the current branch has a tracking branch or not. And\n> what's worse, when the 'push.default' config variable is set to\n> `matching`, it's hard to tell whether the current branch has already\n> been pushed out or not at all [1].\n\nThat description of the problem you are trying to solve makes (sort\nof) sense.\n\n> So always show the remote tracking branch in the output of \"git status\"\n> and other commands will help users to see where the current branch\n> will push to and pull from. E.g.\n>\n>     $ git status\n>     # On branch master\n>     # Your branch is identical to 'origin/master'.\n>     #\n>     ...\n>\n>     $ git status -bs\n>     ## master...origin/master\n>     ...\n\nHmmph.\n\nI do not know if this will help any case you described above, even\nthough this might help some other cases.  The added output is to\nalways show the current branch and its upstream, but the thing is,\nthe original issue in $gmane/198703 was *not* that the current\nbranch was pushed and up to date.  It was that there was no current\nbranch to be pushed.  The same thing would happen if you are on a\nlocal branch that is not set to be pushed to the other side\n(e.g. the configuration is set to \"matching\" and there is no such\nbranch on the other end).\n\n\"Your branch is identical to\" will be given only if your branch is\nset to be pushed out, no?  For the user to tell what is going on,\nthe user has to notice the lack of this extra line in the output,\nand noticing the lack of anything is much unlikely.\n"},{"id":"225020","messageId":"8b2e7fa581846aca3209b430ac46950ff9d92924.1376146168.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"7vob964l6v.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-10T15:05:09Z","receivedAt":"2013-08-10T15:05:09Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"2013/8/10 Junio C Hamano <gitster@pobox.com>:\n> Jiang Xin <worldhello.net@gmail.com> writes:\n>\n>> So always show the remote tracking branch in the output of \"git status\"\n>> and other commands will help users to see where the current branch\n>> will push to and pull from. E.g.\n>> ...\n>\n> Hmmph.\n>\n> I do not know if this will help any case you described above, even\n> though this might help some other cases.  The added output is to\n> always show the current branch and its upstream, but the thing is,\n> the original issue in $gmane/198703 was *not* that the current\n> branch was pushed and up to date.  It was that there was no current\n> branch to be pushed.  The same thing would happen if you are on a\n> local branch that is not set to be pushed to the other side\n> (e.g. the configuration is set to \"matching\" and there is no such\n> branch on the other end).\n>\n\nHow about write the commit log like this:\n\n-- 8< --\nFrom: Jiang Xin <worldhello.net@gmail.com>\nDate: Wed, 7 Aug 2013 21:45:01 +0800\nSubject: [PATCH v4] status: always show tracking branch even no change\n\nIf the current branch has an upstream branch, and there are changes\nbetween the current branch and its upstream, some commands (such as\n\"git status\", \"git status -bs\", and \"git checkout\") will report their\nrelationship. E.g.\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    ...\n\n    $ git status -bs\n    ## master...origin/master [ahead 1]\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is ahead of 'origin/master' by 1 commit.\n    ...\n\nWith this patch, the relationship between the current branch its\nupstream will be reported always even if there is no difference\nbetween them. E.g.\n\n    $ git status\n    # On branch master\n    # Your branch is identical to 'origin/master'.\n    ...\n\n    $ git status -bs\n    ## master...origin/master\n    ...\n\n    $ git checkout master\n    Already on 'master'\n    Your branch is identical to 'origin/master'.\n    ...\n\nThen if there is no tracking info reported, the user may need to do\nsomething. Maybe the current branch is a new branch that needs to be\npushed out, or maybe it's a branch which should add remote tracking\nsettings.\n\nThis patch changes the return value of function stat_tracking_info()\nfrom 0 (not report) to 1 (report), when the current branch and its\nremote tracking branch point to the same commit. Also add some test\ncases in t6040.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/branch.c         | 18 +++++-----------\n remote.c                 | 18 +++++++++++-----\n t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----\n wt-status.c              |  5 +++++\n 4 files changed, 73 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0836890..359e75d 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n-\t\t    show_upstream_ref) {\n-\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\t\tif (want_color(branch_use_color))\n-\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\t\telse\n-\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n-\t\t}\n+\tif (!stat_tracking_info(branch, &ours, &theirs))\n \t\treturn;\n-\t}\n \n \tif (show_upstream_ref) {\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n@@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours) {\n+\tif (!ours && !theirs) {\n+\t\tif (ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n+\t} else if (!ours) {\n \t\tif (ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n \t\telse\ndiff --git a/remote.c b/remote.c\nindex 2433467..79766df 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1740,6 +1740,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n+\t/* Set both num_theirs and num_ours as undetermined. */\n+\t*num_theirs = -1;\n+\t*num_ours = -1;\n+\n \t/*\n \t * Nothing to report unless we are marked to build on top of\n \t * somebody else.\n@@ -1758,16 +1762,18 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \ttheirs = lookup_commit_reference(sha1);\n \tif (!theirs)\n \t\treturn 0;\n+\t*num_theirs = 0;\n \n \tif (read_ref(branch->refname, sha1))\n \t\treturn 0;\n \tours = lookup_commit_reference(sha1);\n \tif (!ours)\n \t\treturn 0;\n+\t*num_ours = 0;\n \n-\t/* are we the same? */\n+\t/* are we the same? both num_theirs and num_ours have been set to 0. */\n \tif (theirs == ours)\n-\t\treturn 0;\n+\t\treturn 1;\n \n \t/* Run \"rev-list --left-right ours...theirs\" internally... */\n \trev_argc = 0;\n@@ -1786,8 +1792,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tprepare_revision_walk(&revs);\n \n \t/* ... and count the commits on each side. */\n-\t*num_ours = 0;\n-\t*num_theirs = 0;\n \twhile (1) {\n \t\tstruct commit *c = get_revision(&revs);\n \t\tif (!c)\n@@ -1817,7 +1821,11 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (!num_ours && !num_theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to '%s'.\\n\"),\n+\t\t\tbase);\n+\t} else if (!num_theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..eafce7d 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -28,18 +28,20 @@ test_expect_success setup '\n \t\tgit reset --hard HEAD^ &&\n \t\tgit checkout -b b4 origin &&\n \t\tadvance e &&\n-\t\tadvance f\n+\t\tadvance f &&\n+\t\tgit checkout -b b5 origin\n \t) &&\n \tgit checkout -b follower --track master &&\n \tadvance g\n '\n \n-script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\n+script='s/^..\\(b.\\)[\t 0-9a-f]*\\(\\[\\([^]]*\\)\\]\\)\\{0,1\\}.*/\\1 \\3/p'\n cat >expect <<\\EOF\n b1 ahead 1, behind 1\n b2 ahead 1, behind 1\n b3 behind 1\n b4 ahead 2\n+b5 \n EOF\n \n test_expect_success 'branch -v' '\n@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1\n b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n+b5 origin/master\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '\n \ttest_i18ncmp expect actual\n '\n \n-test_expect_success 'checkout' '\n+test_expect_success 'checkout (diverged from upstream)' '\n \t(\n \t\tcd test && git checkout b1\n \t) >actual &&\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'checkout (identical to upstream)' '\n+\t(\n+\t\tcd test && git checkout b5\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n test_expect_success 'checkout with local tracked branch' '\n \tgit checkout master &&\n \tgit checkout follower >actual &&\n \ttest_i18ngrep \"is ahead of\" actual\n '\n \n-test_expect_success 'status' '\n+test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n \t\tgit checkout b1 >/dev/null &&\n@@ -90,6 +100,42 @@ test_expect_success 'status' '\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'status (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n+cat >expect <<\\EOF\n+## b1...origin/master [ahead 1, behind 1]\n+EOF\n+\n+test_expect_success 'status -s -b (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+## b5...origin/master\n+EOF\n+\n+test_expect_success 'status -s -b (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex ff4b324..39742ff 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1392,6 +1392,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n-- \n1.8.4.rc1.430.g417e2f3\n"},{"id":"225074","messageId":"7vd2pj1lk6.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"8b2e7fa581846aca3209b430ac46950ff9d92924.1376146168.git.worldhello.net@gmail.com","subject":"Re: [PATCH v3] status: always show tracking branch even no change","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-12T06:15:53Z","receivedAt":"2013-08-12T06:15:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> 2013/8/10 Junio C Hamano <gitster@pobox.com>:\n>> Jiang Xin <worldhello.net@gmail.com> writes:\n>>\n>>> So always show the remote tracking branch in the output of \"git status\"\n>>> and other commands will help users to see where the current branch\n>>> will push to and pull from. E.g.\n>>> ...\n>>\n>> Hmmph.\n>>\n>> I do not know if this will help any case you described above, even\n>> though this might help some other cases.  The added output is to\n>> always show the current branch and its upstream, but the thing is,\n>> the original issue in $gmane/198703 was *not* that the current\n>> branch was pushed and up to date.  It was that there was no current\n>> branch to be pushed.  The same thing would happen if you are on a\n>> local branch that is not set to be pushed to the other side\n>> (e.g. the configuration is set to \"matching\" and there is no such\n>> branch on the other end).\n>>\n>\n> How about write the commit log like this:\n> ...\n> Then if there is no tracking info reported, the user may need to do\n> something. Maybe the current branch is a new branch that needs to be\n> pushed out, or maybe it's a branch which should add remote tracking\n> settings.\n\nWould that help anybody, though?\n\nA user who does not notice the _lack_ of mention of the current\nbranch in the feedback from \"git push\" would not notice the lack of\n\"ahead, behind or the same\".\n\nWe could contemplate on saying \"your current branch is not set to be\npushed out to anywhere\" instead of being silent in the case where\nthe output with your patch is silent, but that would make \"status\"\noutput irritatingly chatty when you are on a private topic branch\nthat you never intend to push out except as a part of an integration\nbranch after merging into it, so it is not a good solution either,\nbut at least that would solve the original problem.\n\nIsn't it the real solution to the original poster's problem to make\n\"git push\" explain \"Everything is up to date, and nothing is pushed\"\ncase better?\n\nPerhaps \"git push\" can learn an option to show what the command\nwould push out if there were something to push.  If push.default is\nset to matching and the user is on a branch that does not exist on\nthe receiving end, matching branches will be listed as \"up to date\"\nand the user could notice that his current branch is _not_ among the\nones that are listed.  When there is _no_ branch to be pushed out\n(e.g. there is no matching branches, or you are on a detached HEAD)\nthat \"please explain\" option could really explain whey there is no\nbranch to be pushed out\".\n"},{"id":"225126","messageId":"CANYiYbFGBRV+EP8oV_chKvBsHLAAZeKmt0395_z9QD-bBZtErQ@mail.gmail.com","threadId":"34633","inReplyTo":"7vd2pj1lk6.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-13T04:49:31Z","receivedAt":"2013-08-13T04:49:31Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"2013/8/12 Junio C Hamano <gitster@pobox.com>:\n> Jiang Xin <worldhello.net@gmail.com> writes:\n>\n>> 2013/8/10 Junio C Hamano <gitster@pobox.com>:\n>>> Jiang Xin <worldhello.net@gmail.com> writes:\n>>>\n>>>> So always show the remote tracking branch in the output of \"git status\"\n>>>> and other commands will help users to see where the current branch\n>>>> will push to and pull from. E.g.\n>>>> ...\n>>>\n>>> Hmmph.\n>>>\n>>> I do not know if this will help any case you described above, even\n>>> though this might help some other cases.  The added output is to\n>>> always show the current branch and its upstream, but the thing is,\n>>> the original issue in $gmane/198703 was *not* that the current\n>>> branch was pushed and up to date.  It was that there was no current\n>>> branch to be pushed.  The same thing would happen if you are on a\n>>> local branch that is not set to be pushed to the other side\n>>> (e.g. the configuration is set to \"matching\" and there is no such\n>>> branch on the other end).\n>>>\n>>\n>> How about write the commit log like this:\n>> ...\n>> Then if there is no tracking info reported, the user may need to do\n>> something. Maybe the current branch is a new branch that needs to be\n>> pushed out, or maybe it's a branch which should add remote tracking\n>> settings.\n>\n> Would that help anybody, though?\n\nI will split the patch into two. The 1st patch resolves a real problem:\n\n    branch: not report invalid tracking branch\n\n    Command \"git branch -vv\" will report tracking branches, but invalid\n    tracking branches are also reported. This is because the function\n    stat_tracking_info() can not distinguish whether the upstream branch\n    does not exist, or nothing is changed between one branch and its\n    upstream.\n\n    This patch changes the return value of function stat_tracking_info().\n    Only returns false when there is no tracking branch or the tracking\n    branch is invalid, otherwise true. If the caller does not like to\n    report tracking info when nothing changed between the branch and its\n    upstream, simply checks if num_theirs and num_ours are both 0.\n\nAnd in the 2nd patch, I will not mention \"git push\" (current not be\npushed out ...) any more, and only focus on \"git status\". It's just\na suggestion, may only fit small group of users' taste.\n\n\n-- \nJiang Xin\n"},{"id":"225127","messageId":"96e0ed4f67eaf058466ead9228cad0dcfe1b5c6a.1376369554.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"CANYiYbFGBRV+EP8oV_chKvBsHLAAZeKmt0395_z9QD-bBZtErQ@mail.gmail.com","subject":"[PATCH v5 1/2] branch: not report invalid tracking branch","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-13T04:53:48Z","receivedAt":"2013-08-13T04:53:48Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Command \"git branch -vv\" will report tracking branches, but invalid\ntracking branches are also reported. This is because the function\nstat_tracking_info() can not distinguish whether the upstream branch\ndoes not exist, or nothing is changed between one branch and its\nupstream.\n\nThis patch changes the return value of function stat_tracking_info().\nOnly returns false when there is no tracking branch or the tracking\nbranch is invalid, otherwise true. If the caller does not like to\nreport tracking info when nothing changed between the branch and its\nupstream, simply checks if num_theirs and num_ours are both 0.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/branch.c | 18 +++++-------------\n remote.c         | 24 ++++++++++++------------\n wt-status.c      | 13 +++++++++++--\n 3 files changed, 28 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0836890..359e75d 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n-\t\t    show_upstream_ref) {\n-\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\t\tif (want_color(branch_use_color))\n-\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\t\telse\n-\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n-\t\t}\n+\tif (!stat_tracking_info(branch, &ours, &theirs))\n \t\treturn;\n-\t}\n \n \tif (show_upstream_ref) {\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n@@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours) {\n+\tif (!ours && !theirs) {\n+\t\tif (ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n+\t} else if (!ours) {\n \t\tif (ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n \t\telse\ndiff --git a/remote.c b/remote.c\nindex 2433467..c747936 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n }\n \n /*\n- * Return true if there is anything to report, otherwise false.\n+ * Return false if cannot stat a tracking branch (not exist or invalid),\n+ * otherwise true.\n  */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n {\n@@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n-\t/*\n-\t * Nothing to report unless we are marked to build on top of\n-\t * somebody else.\n-\t */\n+\t/* False unless we are marked to build on top of somebody else. */\n \tif (!branch ||\n \t    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)\n \t\treturn 0;\n \n-\t/*\n-\t * If what we used to build on no longer exists, there is\n-\t * nothing to report.\n-\t */\n+\t/* False if what we used to build on no longer exists */\n \tbase = branch->merge[0]->dst;\n \tif (read_ref(base, sha1))\n \t\treturn 0;\n@@ -1765,9 +1760,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tif (!ours)\n \t\treturn 0;\n \n+\t*num_theirs = 0;\n+\t*num_ours = 0;\n+\n \t/* are we the same? */\n \tif (theirs == ours)\n-\t\treturn 0;\n+\t\treturn 1;\n \n \t/* Run \"rev-list --left-right ours...theirs\" internally... */\n \trev_argc = 0;\n@@ -1786,8 +1784,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tprepare_revision_walk(&revs);\n \n \t/* ... and count the commits on each side. */\n-\t*num_ours = 0;\n-\t*num_theirs = 0;\n \twhile (1) {\n \t\tstruct commit *c = get_revision(&revs);\n \t\tif (!c)\n@@ -1815,6 +1811,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n \t\treturn 0;\n \n+\t/* Nothing to report if neither side has changes. */\n+\tif (!num_ours && !num_theirs)\n+\t\treturn 0;\n+\n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n \tif (!num_theirs) {\ndiff --git a/wt-status.c b/wt-status.c\nindex ff4b324..0c6a3a5 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tbranch = branch_get(s->branch + 11);\n \tif (s->is_initial)\n \t\tcolor_fprintf(s->fp, header_color, _(\"Initial commit on \"));\n+\n+\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\n+\t/*\n+\t * Not report tracking info if no tracking branch found\n+\t * or no difference found.\n+\t */\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\tif (!num_ours && !num_theirs) {\n \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n \t\treturn;\n \t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n-- \n1.8.4.rc1.430.g417e2f3\n"},{"id":"225128","messageId":"6b540dd551924a2e4f60c2892ad4872259c2c1d3.1376369554.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"96e0ed4f67eaf058466ead9228cad0dcfe1b5c6a.1376369554.git.worldhello.net@gmail.com","subject":"[PATCH v5 2/2] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-13T04:53:49Z","receivedAt":"2013-08-13T04:53:49Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"In order to see what the current branch is tracking, one way is using\n\"git branch -v -v\", but branches other than the current are also\nreported. Another way is using \"git status\", such as:\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    ...\n\nBut this will not work if there is no change between the current\nbranch and its upstream. What if report upstream tracking info\nalways even if there is no difference. E.g.\n\n    $ git status\n    # On branch feature1\n    # Your branch is identical to 'github/feature1'.\n    ...\n\n    $ git status -bs\n    ## feature1...github/feature1\n    ...\n\n    $ git checkout feature1\n    Already on 'feature1'\n    Your branch is identical to 'github/feature1'.\n    ...\n\nAlso add some test cases in t6040.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n remote.c                 | 10 ++++-----\n t/t6040-tracking-info.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++----\n wt-status.c              | 13 +++++-------\n 3 files changed, 60 insertions(+), 17 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex c747936..70307f4 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1811,13 +1811,13 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n \t\treturn 0;\n \n-\t/* Nothing to report if neither side has changes. */\n-\tif (!num_ours && !num_theirs)\n-\t\treturn 0;\n-\n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (!num_ours && !num_theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to '%s'.\\n\"),\n+\t\t\tbase);\n+\t} else if (!num_theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..eafce7d 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -28,18 +28,20 @@ test_expect_success setup '\n \t\tgit reset --hard HEAD^ &&\n \t\tgit checkout -b b4 origin &&\n \t\tadvance e &&\n-\t\tadvance f\n+\t\tadvance f &&\n+\t\tgit checkout -b b5 origin\n \t) &&\n \tgit checkout -b follower --track master &&\n \tadvance g\n '\n \n-script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\n+script='s/^..\\(b.\\)[\t 0-9a-f]*\\(\\[\\([^]]*\\)\\]\\)\\{0,1\\}.*/\\1 \\3/p'\n cat >expect <<\\EOF\n b1 ahead 1, behind 1\n b2 ahead 1, behind 1\n b3 behind 1\n b4 ahead 2\n+b5 \n EOF\n \n test_expect_success 'branch -v' '\n@@ -56,6 +58,7 @@ b1 origin/master: ahead 1, behind 1\n b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n+b5 origin/master\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -67,20 +70,27 @@ test_expect_success 'branch -vv' '\n \ttest_i18ncmp expect actual\n '\n \n-test_expect_success 'checkout' '\n+test_expect_success 'checkout (diverged from upstream)' '\n \t(\n \t\tcd test && git checkout b1\n \t) >actual &&\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'checkout (identical to upstream)' '\n+\t(\n+\t\tcd test && git checkout b5\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n test_expect_success 'checkout with local tracked branch' '\n \tgit checkout master &&\n \tgit checkout follower >actual &&\n \ttest_i18ngrep \"is ahead of\" actual\n '\n \n-test_expect_success 'status' '\n+test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n \t\tgit checkout b1 >/dev/null &&\n@@ -90,6 +100,42 @@ test_expect_success 'status' '\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'status (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n+cat >expect <<\\EOF\n+## b1...origin/master [ahead 1, behind 1]\n+EOF\n+\n+test_expect_success 'status -s -b (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+## b5...origin/master\n+EOF\n+\n+test_expect_success 'status -s -b (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 0c6a3a5..627b59e 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1383,24 +1383,21 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \n \tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \n-\t/*\n-\t * Not report tracking info if no tracking branch found\n-\t * or no difference found.\n-\t */\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n \t\treturn;\n \t}\n-\tif (!num_ours && !num_theirs) {\n-\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\treturn;\n-\t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n-- \n1.8.4.rc1.430.g417e2f3\n"},{"id":"225204","messageId":"7vfvucuwm7.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"96e0ed4f67eaf058466ead9228cad0dcfe1b5c6a.1376369554.git.worldhello.net@gmail.com","subject":"Re: [PATCH v5 1/2] branch: not report invalid tracking branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-14T15:21:04Z","receivedAt":"2013-08-14T15:21:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> Command \"git branch -vv\" will report tracking branches, but invalid\n> tracking branches are also reported. This is because the function\n> stat_tracking_info() can not distinguish whether the upstream branch\n> does not exist, or nothing is changed between one branch and its\n> upstream.\n>\n> This patch changes the return value of function stat_tracking_info().\n> Only returns false when there is no tracking branch or the tracking\n> branch is invalid, otherwise true. If the caller does not like to\n> report tracking info when nothing changed between the branch and its\n> upstream, simply checks if num_theirs and num_ours are both 0.\n>\n> Signed-off-by: Jiang Xin <worldhello.net@gmail.com>\n> ---\n>  builtin/branch.c | 18 +++++-------------\n>  remote.c         | 24 ++++++++++++------------\n>  wt-status.c      | 13 +++++++++++--\n>  3 files changed, 28 insertions(+), 27 deletions(-)\n>\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index 0836890..359e75d 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n>  \tstruct branch *branch = branch_get(branch_name);\n>  \tstruct strbuf fancy = STRBUF_INIT;\n>  \n> -\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n> -\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n> -\t\t    show_upstream_ref) {\n> -\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n> -\t\t\tif (want_color(branch_use_color))\n> -\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n> -\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n> -\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n> -\t\t\telse\n> -\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n> -\t\t}\n> +\tif (!stat_tracking_info(branch, &ours, &theirs))\n>  \t\treturn;\n> -\t}\n>  \n>  \tif (show_upstream_ref) {\n>  \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n> @@ -448,7 +437,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n>  \t\t\tstrbuf_addstr(&fancy, ref);\n>  \t}\n>  \n> -\tif (!ours) {\n> +\tif (!ours && !theirs) {\n> +\t\tif (ref)\n> +\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n\nMental note: the updated stat_tracking_info() says \"something to\nreport exists\" when the current branch and its @{u} are the same,\nand we report the branch here.\n\n> +\t} else if (!ours) {\n>  \t\tif (ref)\n>  \t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n\nThis is not a fault of your change, but the logic to show the\nupstream ref is unnecessarily unclear due to variable cascading.\nThe master switch \"show_upstream_ref\" is what is used to ask this to\nfill the name of the upstream ref, and \"ref\" is made non-NULL only\nwhen \"show_upstream_ref\" is true.  Also \"fancy\" would be non-empty\nonly in that case, so this \"if (ref)\" could be any one of these:\n\n        if (show_upstream_ref)\n\tif (ref)\n        if (fancy.len)\n\nIt is disturbing that the middle one is used.  If you take the\nstance that the code should reflect the logic, the first one\n(i.e. \"we were asked to show upstream ref, so we show it here\")\nmakes the most sense.  If you take the stance that the code should\nbe safe with the low-level implementation, the last one (i.e. \"we\nare showing what is in fancy, if we have prepared something to show\nin that buffer\") makes sense.  The middle one is the least logical\nthing to base the decision on.\n\n> diff --git a/remote.c b/remote.c\n> index 2433467..c747936 100644\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n>  }\n>  \n>  /*\n> - * Return true if there is anything to report, otherwise false.\n> + * Return false if cannot stat a tracking branch (not exist or invalid),\n> + * otherwise true.\n>   */\n>  int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n>  {\n> @@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n>  \tconst char *rev_argv[10], *base;\n>  \tint rev_argc;\n>  \n> -\t/*\n> -\t * Nothing to report unless we are marked to build on top of\n> -\t * somebody else.\n> -\t */\n> +\t/* False unless we are marked to build on top of somebody else. */\n\nAren't these saying the same thing?  I'd rather see the comment say\n\"nothing/something to report\", instead of \"false/true\".  The latter\ncan be read from the value returned in the code, and writing that in\nthe comment is redundant.  The former tells the reader what that\n\"false\" _means_, which is the whole point of adding a comment.\n\n>  \tif (!branch ||\n>  \t    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)\n>  \t\treturn 0;\n>  \n> -\t/*\n> -\t * If what we used to build on no longer exists, there is\n> -\t * nothing to report.\n> -\t */\n> +\t/* False if what we used to build on no longer exists */\n>  \tbase = branch->merge[0]->dst;\n>  \tif (read_ref(base, sha1))\n>  \t\treturn 0;\n\nLikewise.\n\n> +\t*num_theirs = 0;\n> +\t*num_ours = 0;\n> +\n>  \t/* are we the same? */\n>  \tif (theirs == ours)\n> -\t\treturn 0;\n> +\t\treturn 1;\n\nShouldn't these zero assignments belong to this condition?  I.e.\n\n\tif (theirs == ours) {\n        \t*num_theirs = *num_ours = 0;\n                return 1;\n\t}\n\n> @@ -1786,8 +1784,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n>  \tprepare_revision_walk(&revs);\n>  \n>  \t/* ... and count the commits on each side. */\n> -\t*num_ours = 0;\n> -\t*num_theirs = 0;\n>  \twhile (1) {\n>  \t\tstruct commit *c = get_revision(&revs);\n>  \t\tif (!c)\n> @@ -1815,6 +1811,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n>  \tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n>  \t\treturn 0;\n>  \n> +\t/* Nothing to report if neither side has changes. */\n> +\tif (!num_ours && !num_theirs)\n> +\t\treturn 0;\n\nAs far as I can tell, all callers of stat_tracking_info() pass\nnon-NULL pointers to these two parameters, with or without your\npatch.  Can this ever trigger?\n\nThe changes you made to builtin/branch.c seems to expect that\nreturned *num_ours and *num_theirs could both be 0, so it does not\nlook like the above is a typo of\n\n\tif (!*num_ours && !*num_theirs)\n        \treturn 0;\n\neven though the comment \"neither side has changes\" seems to indicate\nthat was what was meant.\n\nI am puzzled by this incoherence between the callers and the callee.\n\n> diff --git a/wt-status.c b/wt-status.c\n> index ff4b324..0c6a3a5 100644\n> --- a/wt-status.c\n> +++ b/wt-status.c\n> @@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n>  \tbranch = branch_get(s->branch + 11);\n>  \tif (s->is_initial)\n>  \t\tcolor_fprintf(s->fp, header_color, _(\"Initial commit on \"));\n> +\n> +\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n> +\n> +\t/*\n> +\t * Not report tracking info if no tracking branch found\n> +\t * or no difference found.\n> +\t */\n>  \tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n> -\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n> +\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n> +\t\treturn;\n> +\t}\n> +\tif (!num_ours && !num_theirs) {\n>  \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n>  \t\treturn;\n>  \t}\n>  \n>  \tbase = branch->merge[0]->dst;\n>  \tbase = shorten_unambiguous_ref(base, 0);\n> -\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n>  \tcolor_fprintf(s->fp, header_color, \"...\");\n>  \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n"},{"id":"225205","messageId":"7vbo50uvty.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"96e0ed4f67eaf058466ead9228cad0dcfe1b5c6a.1376369554.git.worldhello.net@gmail.com","subject":"Re: [PATCH v5 1/2] branch: not report invalid tracking branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-14T15:38:01Z","receivedAt":"2013-08-14T15:38:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> Command \"git branch -vv\" will report tracking branches, but invalid\n> tracking branches are also reported. This is because the function\n> stat_tracking_info() can not distinguish whether the upstream branch\n> does not exist, or nothing is changed between one branch and its\n> upstream.\n\nI am guessing that by \"invalid\", you used to have another branch\n(possibly a remote one) you built a branch on (hence the upstream of\nthe latter is set to the former) and the former branch no longer\nexists.\n\nShouldn't that case reported a bit more specially?  After doing this:\n\n\tgit init\n        git commit --allow-empty -m initial ;# on master\n        git branch topicbase\n        git checkout -t -b topic topicbase\n        git commit --allow-empty -m topic ;# on topic\n        git branch -d topicbase\n\nthe branch \"topic\" _thinks_ it is still based on \"topicbase\", but of\ncourse \"git log @{u}..\" will fail.\n\nA few thought-alouds:\n\n - Perhaps \"git branch -d topicbase\" should have warned that there\n   are some branches that are based on it?  Should it have failed?\n   Or should it automatically removed branch.*.merge entries that\n   point at it (while warning)?\n\n - The operation that removes the @{u} of some branch does not have\n   to be \"git branch -d\".  It could be \"remote --prune\", and it does\n   not make much sense to fail that operation, as what is gone from\n   the other side is gone, and the point of having remote tracking\n   branches is to keep a faithful copy of the observed status of the\n   remote.  It implies that failing \"git branch -d topicbase\" is not\n   a good idea.  Also removing the branch.*.merge automatically is\n   probably not what the user wants (at least, the name would hint\n   something, even after the topicbase branch is gone).\n\nSo \"git branch -v -v [topic]\" would want to still say that topic is\nbased on topicbranch, even though the latter is gone and there is no\nlonger a real \"building on\" relationship.\n\nE.g. before \"git branch -d topicbase\" we would see something like:\n\n    $ git branch -v -v\n      master    e67ac84 initial\n    * topic     3fc0f2a [topicbase: ahead 1] topic\n      topicbase e67ac84 [master] initial\n\nand after it, we currently see:\n\n    $ git branch -v -v\n      master    e67ac84 initial\n    * topic     3fc0f2a [topicbase] topic\n      topicbase e67ac84 [master] initial\n\nbut we may want to say:\n\n    $ git branch -v -v\n      master    e67ac84 initial\n    * topic     3fc0f2a [topicbase (gone)] topic\n      topicbase e67ac84 [master] initial\n\nor something.\n\nIn order to distinguish these three cases (i.e. no tracking, with\nconfigured but no longer valid tracking, and with tracking), you\nwould need more than true/false.\n\n> This patch changes the return value of function stat_tracking_info().\n> Only returns false when there is no tracking branch or the tracking\n> branch is invalid, otherwise true.\n\nInstead, you would need -1 (with \"gone\" base), 0 (no base), 1 (with\nbase).\n\nThis is a tangent, but we might want to rename stat_tracking_info().\nA branch A building on top of another branch B does not mean A\n\"tracks\" B.  The wording is a source of confusion.\n"},{"id":"225242","messageId":"CANYiYbHC1oXjMy9tb7vRJmq2LMzk0yXwjm_kMoM-U7cqvrjiZA@mail.gmail.com","threadId":"34633","inReplyTo":"7vfvucuwm7.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v5 1/2] branch: not report invalid tracking branch","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-15T02:14:40Z","receivedAt":"2013-08-15T02:14:40Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"2013/8/14 Junio C Hamano <gitster@pobox.com>\n> >  /*\n> > - * Return true if there is anything to report, otherwise false.\n> > + * Return false if cannot stat a tracking branch (not exist or invalid),\n> > + * otherwise true.\n> >   */\n> >  int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n> >  {\n> > @@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n> >       const char *rev_argv[10], *base;\n> >       int rev_argc;\n> >\n> > -     /*\n> > -      * Nothing to report unless we are marked to build on top of\n> > -      * somebody else.\n> > -      */\n> > +     /* False unless we are marked to build on top of somebody else. */\n>\n> Aren't these saying the same thing?  I'd rather see the comment say\n> \"nothing/something to report\", instead of \"false/true\".  The latter\n> can be read from the value returned in the code, and writing that in\n> the comment is redundant.  The former tells the reader what that\n> \"false\" _means_, which is the whole point of adding a comment.\n\nMaybe \"Cannot stat unless ...\" is better than \"Nothing to report unless ...\",\nbecause this patch change the meaning of returns of stat_tracking_info().\nAnd I have already updated the comments for this function.\n\n>\n> > +     *num_theirs = 0;\n> > +     *num_ours = 0;\n> > +\n> >       /* are we the same? */\n> >       if (theirs == ours)\n> > -             return 0;\n> > +             return 1;\n>\n> Shouldn't these zero assignments belong to this condition?  I.e.\n>\n>         if (theirs == ours) {\n>                 *num_theirs = *num_ours = 0;\n>                 return 1;\n>         }\n\nI will refactor like this,\n\n> > @@ -1786,8 +1784,6 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n> >       prepare_revision_walk(&revs);\n> >\n> >       /* ... and count the commits on each side. */\n> > -     *num_ours = 0;\n> > -     *num_theirs = 0;\n> >       while (1) {\n> >               struct commit *c = get_revision(&revs);\n> >               if (!c)\n\nand these two variables(*num_ours and *num_theirs) have to be\ninitialized here again.\n\n> > @@ -1815,6 +1811,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n> >       if (!stat_tracking_info(branch, &num_ours, &num_theirs))\n> >               return 0;\n> >\n> > +     /* Nothing to report if neither side has changes. */\n> > +     if (!num_ours && !num_theirs)\n> > +             return 0;\n>\n> As far as I can tell, all callers of stat_tracking_info() pass\n> non-NULL pointers to these two parameters, with or without your\n> patch.  Can this ever trigger?\n>\n> The changes you made to builtin/branch.c seems to expect that\n> returned *num_ours and *num_theirs could both be 0, so it does not\n> look like the above is a typo of\n>\n>         if (!*num_ours && !*num_theirs)\n>                 return 0;\n>\n\nIt's really easy to make people puzzled, since these two hunks in this patch\nboth have two similar variables: num_ours and num_theirs. But they are\ndifferent.\n\nIn previous hunk, num_ours and num_theres are from stat_tracking_info(),\nand they are pointers.\n\n    int stat_tracking_info(struct branch *branch,\n                           int *num_ours,\n                           int *num_theirs)\n\nBut in this hunk, num_ours and num_theres are defined as integers in\nfunciton  format_tracking_info().\n\n    int format_tracking_info(struct branch *branch, struct strbuf *sb)\n    {\n        int num_ours, num_theirs;\n\nTo make it clear, I should change the variables name to ours and theirs\njust like function fill_tracking_info() in builtin/branch.c.\n\n-- \nJiang Xin\n"},{"id":"225272","messageId":"6bc0643a5fa0fae03be6fdb59f63075be1e4d983.1376590264.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"7vbo50uvty.fsf@alter.siamese.dyndns.org","subject":"[PATCH v6 1/3] branch: not report invalid tracking branch","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-15T18:11:21Z","receivedAt":"2013-08-15T18:11:21Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Command \"git branch -vv\" will report tracking branches, but invalid\ntracking branches are also reported. This is because the function\nstat_tracking_info() can not distinguish whether the upstream branch\ndoes not exist, or nothing is changed between one branch and its\nupstream.\n\nThis patch changes the return value of function stat_tracking_info().\nOnly returns false when there is no tracking branch or the tracking\nbranch is invalid, otherwise true. If the caller does not like to\nreport tracking info when nothing changed between the branch and its\nupstream, simply checks if num_theirs and num_ours are both 0.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/branch.c         | 24 ++++++++----------------\n remote.c                 | 43 ++++++++++++++++++++++---------------------\n t/t6040-tracking-info.sh |  8 ++++++--\n wt-status.c              | 13 +++++++++++--\n 4 files changed, 47 insertions(+), 41 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0903763..3e016a6 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n-\t\t    show_upstream_ref) {\n-\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\t\tif (want_color(branch_use_color))\n-\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\t\telse\n-\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n-\t\t}\n+\tif (!stat_tracking_info(branch, &ours, &theirs))\n \t\treturn;\n-\t}\n \n \tif (show_upstream_ref) {\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n@@ -448,19 +437,22 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours) {\n-\t\tif (ref)\n+\tif (!ours && !theirs) {\n+\t\tif (show_upstream_ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n+\t} else if (!ours) {\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n \t\telse\n \t\t\tstrbuf_addf(stat, _(\"[behind %d]\"), theirs);\n \n \t} else if (!theirs) {\n-\t\tif (ref)\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d]\"), fancy.buf, ours);\n \t\telse\n \t\t\tstrbuf_addf(stat, _(\"[ahead %d]\"), ours);\n \t} else {\n-\t\tif (ref)\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d, behind %d]\"),\n \t\t\t\t    fancy.buf, ours, theirs);\n \t\telse\ndiff --git a/remote.c b/remote.c\nindex 2433467..26bd543 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n }\n \n /*\n- * Return true if there is anything to report, otherwise false.\n+ * Return false if cannot stat a tracking branch (not exist or invalid),\n+ * otherwise true.\n  */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n {\n@@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n-\t/*\n-\t * Nothing to report unless we are marked to build on top of\n-\t * somebody else.\n-\t */\n+\t/* Cannot stat unless we are marked to build on top of somebody else. */\n \tif (!branch ||\n \t    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)\n \t\treturn 0;\n \n-\t/*\n-\t * If what we used to build on no longer exists, there is\n-\t * nothing to report.\n-\t */\n+\t/* Cannot stat if what we used to build on no longer exists */\n \tbase = branch->merge[0]->dst;\n \tif (read_ref(base, sha1))\n \t\treturn 0;\n@@ -1766,8 +1761,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \t\treturn 0;\n \n \t/* are we the same? */\n-\tif (theirs == ours)\n-\t\treturn 0;\n+\tif (theirs == ours) {\n+\t\t*num_theirs = *num_ours = 0;\n+\t\treturn 1;\n+\t}\n \n \t/* Run \"rev-list --left-right ours...theirs\" internally... */\n \trev_argc = 0;\n@@ -1809,31 +1806,35 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n  */\n int format_tracking_info(struct branch *branch, struct strbuf *sb)\n {\n-\tint num_ours, num_theirs;\n+\tint ours, theirs;\n \tconst char *base;\n \n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n+\tif (!stat_tracking_info(branch, &ours, &theirs))\n+\t\treturn 0;\n+\n+\t/* Nothing to report if neither side has changes. */\n+\tif (!ours && !theirs)\n \t\treturn 0;\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\n-\t\t\t   num_ours),\n-\t\t\tbase, num_ours);\n+\t\t\t   ours),\n+\t\t\tbase, ours);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git push\\\" to publish your local commits)\\n\"));\n-\t} else if (!num_ours) {\n+\t} else if (!ours) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is behind '%s' by %d commit, \"\n \t\t\t       \"and can be fast-forwarded.\\n\",\n \t\t\t   \"Your branch is behind '%s' by %d commits, \"\n \t\t\t       \"and can be fast-forwarded.\\n\",\n-\t\t\t   num_theirs),\n-\t\t\tbase, num_theirs);\n+\t\t\t   theirs),\n+\t\t\tbase, theirs);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git pull\\\" to update your local branch)\\n\"));\n@@ -1845,8 +1846,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\t\t   \"Your branch and '%s' have diverged,\\n\"\n \t\t\t       \"and have %d and %d different commits each, \"\n \t\t\t       \"respectively.\\n\",\n-\t\t\t   num_theirs),\n-\t\t\tbase, num_ours, num_theirs);\n+\t\t\t   theirs),\n+\t\t\tbase, ours, theirs);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git pull\\\" to merge the remote branch into yours)\\n\"));\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..471dd64 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -28,10 +28,14 @@ test_expect_success setup '\n \t\tgit reset --hard HEAD^ &&\n \t\tgit checkout -b b4 origin &&\n \t\tadvance e &&\n-\t\tadvance f\n+\t\tadvance f &&\n+\t\tgit checkout -b brokenbase origin &&\n+\t\tgit checkout -b b5 --track brokenbase &&\n+\t\tadvance g &&\n+\t\tgit branch -d brokenbase\n \t) &&\n \tgit checkout -b follower --track master &&\n-\tadvance g\n+\tadvance h\n '\n \n script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\ndiff --git a/wt-status.c b/wt-status.c\nindex ff4b324..0c6a3a5 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tbranch = branch_get(s->branch + 11);\n \tif (s->is_initial)\n \t\tcolor_fprintf(s->fp, header_color, _(\"Initial commit on \"));\n+\n+\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\n+\t/*\n+\t * Not report tracking info if no tracking branch found\n+\t * or no difference found.\n+\t */\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\tif (!num_ours && !num_theirs) {\n \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n \t\treturn;\n \t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n-- \n1.8.4.rc2.478.g12f0bfd.dirty\n"},{"id":"225273","messageId":"8db143908bc969bbe1d720479fb6214729f7b1ae.1376590264.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"6bc0643a5fa0fae03be6fdb59f63075be1e4d983.1376590264.git.worldhello.net@gmail.com","subject":"[PATCH v6 2/3] branch: report invalid tracking branch as broken","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-15T18:11:22Z","receivedAt":"2013-08-15T18:11:22Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"If a branch has been set to track a upstream, but the upstream branch\nis missing or invalid, the tracking info is silently ignored in the\noutput of some commands such as \"git branch -vv\" and \"git status\",\nas if there were no such tracking settings.\n\nJunio suggested broken upstream should be reported [1]. E.g.\n\n    $ git branch -v -v\n      master    e67ac84 initial\n    * topic     3fc0f2a [topicbase: broken] topic\n\n    $ git status\n    # On branch topic\n    # Your branch is based on a broken ref 'topicbase'.\n    #   (use \"git branch --unset-upstream\" to fixup)\n    ...\n\n    $ git status -b -s\n    ## topic...topicbase [broken]\n    ...\n\nIn order to do like that, we need to distinguish these three cases\n(i.e. no tracking, with configured but no longer valid tracking, and\nwith tracking) in function stat_tracking_info(). So the refactored\nfunction stat_tracking_info() has three return values: -1 (with \"gone\"\nbase), 0 (no base), and 1 (with base).\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/231830/focus=232288\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/branch.c         | 17 +++++++++++++++--\n remote.c                 | 43 ++++++++++++++++++++++++++++++------------\n t/t6040-tracking-info.sh | 49 ++++++++++++++++++++++++++++++++++++++++++++++--\n wt-status.c              | 27 ++++++++++++++++----------\n 4 files changed, 110 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 3e016a6..247785e 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -423,9 +423,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tchar *ref = NULL;\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n+\tint broken_upstream = 0;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs))\n+\tswitch (stat_tracking_info(branch, &ours, &theirs)) {\n+\tcase 0:\n+\t\t/* Not set upstream. */\n \t\treturn;\n+\tcase -1:\n+\t\t/* Upstream is missing or invalid. */\n+\t\tbroken_upstream = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n \n \tif (show_upstream_ref) {\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n@@ -437,7 +447,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours && !theirs) {\n+\tif (broken_upstream) {\n+\t\tif (show_upstream_ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s: broken]\"), fancy.buf);\n+\t} else if (!ours && !theirs) {\n \t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n \t} else if (!ours) {\ndiff --git a/remote.c b/remote.c\nindex 26bd543..aa87381 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1729,8 +1729,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n }\n \n /*\n- * Return false if cannot stat a tracking branch (not exist or invalid),\n- * otherwise true.\n+ * Compare a branch with its tracking branch, and save their differences\n+ * (number of commits) in *num_ours and *num_theirs.\n+ *\n+ * Return 0 if branch has no upstream, -1 if upstream is missing or invalid,\n+ * otherwise 1.\n  */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n {\n@@ -1749,16 +1752,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \t/* Cannot stat if what we used to build on no longer exists */\n \tbase = branch->merge[0]->dst;\n \tif (read_ref(base, sha1))\n-\t\treturn 0;\n+\t\treturn -1;\n \ttheirs = lookup_commit_reference(sha1);\n \tif (!theirs)\n-\t\treturn 0;\n+\t\treturn -1;\n \n \tif (read_ref(branch->refname, sha1))\n-\t\treturn 0;\n+\t\treturn -1;\n \tours = lookup_commit_reference(sha1);\n \tif (!ours)\n-\t\treturn 0;\n+\t\treturn -1;\n \n \t/* are we the same? */\n \tif (theirs == ours) {\n@@ -1808,17 +1811,33 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n {\n \tint ours, theirs;\n \tconst char *base;\n+\tint broken_upstream = 0;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs))\n-\t\treturn 0;\n-\n-\t/* Nothing to report if neither side has changes. */\n-\tif (!ours && !theirs)\n+\tswitch (stat_tracking_info(branch, &ours, &theirs)) {\n+\tcase 0:\n+\t\t/* Not set upstream. */\n \t\treturn 0;\n+\tcase -1:\n+\t\t/* Upstream is missing or invalid. */\n+\t\tbroken_upstream = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* Nothing to report if neither side has changes. */\n+\t\tif (!ours && !theirs)\n+\t\t\treturn 0;\n+\t\tbreak;\n+\t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!theirs) {\n+\tif (broken_upstream) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is based on a broken ref '%s'.\\n\"),\n+\t\t\tbase);\n+\t\tif (advice_status_hints)\n+\t\t\tstrbuf_addf(sb,\n+\t\t\t\t_(\"  (use \\\"git branch --unset-upstream\\\" to fixup)\\n\"));\n+\t} else if (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 471dd64..e362a01 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -60,6 +60,7 @@ b1 origin/master: ahead 1, behind 1\n b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n+b5 brokenbase: broken\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -71,7 +72,7 @@ test_expect_success 'branch -vv' '\n \ttest_i18ncmp expect actual\n '\n \n-test_expect_success 'checkout' '\n+test_expect_success 'checkout (diverged from upstream)' '\n \t(\n \t\tcd test && git checkout b1\n \t) >actual &&\n@@ -84,7 +85,15 @@ test_expect_success 'checkout with local tracked branch' '\n \ttest_i18ngrep \"is ahead of\" actual\n '\n \n-test_expect_success 'status' '\n+test_expect_success 'checkout (broken upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5\n+\t) >actual &&\n+\ttest_i18ngrep \"is based on a broken ref\" actual\n+'\n+\n+test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n \t\tgit checkout b1 >/dev/null &&\n@@ -94,6 +103,42 @@ test_expect_success 'status' '\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'status (broken upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"is based on a broken ref\" actual\n+'\n+\n+cat >expect <<\\EOF\n+## b1...origin/master [ahead 1, behind 1]\n+EOF\n+\n+test_expect_success 'status -s -b (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+## b5...brokenbase [broken]\n+EOF\n+\n+test_expect_success 'status -s -b (broken upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 0c6a3a5..60164d4 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1363,6 +1363,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tconst char *base;\n \tconst char *branch_name;\n \tint num_ours, num_theirs;\n+\tint broken_upstream = 0;\n \n \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"## \");\n \n@@ -1383,17 +1384,21 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \n \tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \n-\t/*\n-\t * Not report tracking info if no tracking branch found\n-\t * or no difference found.\n-\t */\n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\treturn;\n-\t}\n-\tif (!num_ours && !num_theirs) {\n+\tswitch (stat_tracking_info(branch, &num_ours, &num_theirs)) {\n+\tcase 0:\n+\t\t/* Not report tracking info if no tracking branch found. */\n \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n \t\treturn;\n+\tcase -1:\n+\t\t/* Upstream is missing or invalid. */\n+\t\tbroken_upstream = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\tif (!num_ours && !num_theirs) {\n+\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\t\treturn;\n+\t\t}\n+\t\tbreak;\n \t}\n \n \tbase = branch->merge[0]->dst;\n@@ -1402,7 +1407,9 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n \tcolor_fprintf(s->fp, header_color, \" [\");\n-\tif (!num_ours) {\n+\tif (broken_upstream) {\n+\t\tcolor_fprintf(s->fp, header_color, _(\"broken\"));\n+\t} else if (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n \t\tcolor_fprintf(s->fp, branch_color_remote, \"%d\", num_theirs);\n \t} else if (!num_theirs) {\n-- \n1.8.4.rc2.478.g12f0bfd.dirty\n"},{"id":"225274","messageId":"224af6e4fce9004aa50ea0c11c703107857c46f0.1376590264.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"6bc0643a5fa0fae03be6fdb59f63075be1e4d983.1376590264.git.worldhello.net@gmail.com","subject":"[PATCH v6 3/3] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-15T18:11:23Z","receivedAt":"2013-08-15T18:11:23Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"In order to see what the current branch is tracking, one way is using\n\"git branch -v -v\", but branches other than the current are also\nreported. Another way is using \"git status\", such as:\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    ...\n\nBut this will not work if there is no change between the current\nbranch and its upstream. What if report upstream tracking info\nalways even if there is no difference. E.g.\n\n    $ git status\n    # On branch feature1\n    # Your branch is identical to 'github/feature1'.\n    ...\n\n    $ git status -bs\n    ## feature1...github/feature1\n    ...\n\n    $ git checkout feature1\n    Already on 'feature1'\n    Your branch is identical to 'github/feature1'.\n    ...\n\nAlso add some test cases in t6040.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n remote.c                 |  7 ++++---\n t/t6040-tracking-info.sh | 34 +++++++++++++++++++++++++++++++++-\n wt-status.c              |  9 +++++----\n 3 files changed, 42 insertions(+), 8 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex aa87381..1137394 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1822,9 +1822,6 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\tbroken_upstream = 1;\n \t\tbreak;\n \tdefault:\n-\t\t/* Nothing to report if neither side has changes. */\n-\t\tif (!ours && !theirs)\n-\t\t\treturn 0;\n \t\tbreak;\n \t}\n \n@@ -1837,6 +1834,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git branch --unset-upstream\\\" to fixup)\\n\"));\n+\t} else if (!ours && !theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to '%s'.\\n\"),\n+\t\t\tbase);\n \t} else if (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex e362a01..404b629 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -32,7 +32,8 @@ test_expect_success setup '\n \t\tgit checkout -b brokenbase origin &&\n \t\tgit checkout -b b5 --track brokenbase &&\n \t\tadvance g &&\n-\t\tgit branch -d brokenbase\n+\t\tgit branch -d brokenbase &&\n+\t\tgit checkout -b b6 origin\n \t) &&\n \tgit checkout -b follower --track master &&\n \tadvance h\n@@ -61,6 +62,7 @@ b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n b5 brokenbase: broken\n+b6 origin/master\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -93,6 +95,13 @@ test_expect_success 'checkout (broken upstream)' '\n \ttest_i18ngrep \"is based on a broken ref\" actual\n '\n \n+test_expect_success 'checkout (identical to upstream)' '\n+\t(\n+\t\tcd test && git checkout b6\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n@@ -113,6 +122,16 @@ test_expect_success 'status (broken upstream)' '\n \ttest_i18ngrep \"is based on a broken ref\" actual\n '\n \n+test_expect_success 'status (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b6 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n cat >expect <<\\EOF\n ## b1...origin/master [ahead 1, behind 1]\n EOF\n@@ -139,6 +158,19 @@ test_expect_success 'status -s -b (broken upstream)' '\n \ttest_i18ncmp expect actual\n '\n \n+cat >expect <<\\EOF\n+## b6...origin/master\n+EOF\n+\n+test_expect_success 'status -s -b (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b6 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 60164d4..c66963c 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1394,10 +1394,6 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \t\tbroken_upstream = 1;\n \t\tbreak;\n \tdefault:\n-\t\tif (!num_ours && !num_theirs) {\n-\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\t\treturn;\n-\t\t}\n \t\tbreak;\n \t}\n \n@@ -1406,6 +1402,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!broken_upstream && !num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (broken_upstream) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"broken\"));\n-- \n1.8.4.rc2.478.g12f0bfd.dirty\n"},{"id":"225275","messageId":"7vmwoire82.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"8db143908bc969bbe1d720479fb6214729f7b1ae.1376590264.git.worldhello.net@gmail.com","subject":"Re: [PATCH v6 2/3] branch: report invalid tracking branch as broken","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-15T18:38:53Z","receivedAt":"2013-08-15T18:38:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> If a branch has been set to track a upstream, but the upstream branch\n> is missing or invalid, the tracking info is silently ignored in the\n> output of some commands such as \"git branch -vv\" and \"git status\",\n> as if there were no such tracking settings.\n>\n> Junio suggested broken upstream should be reported [1]. E.g.\n>\n>     $ git branch -v -v\n>       master    e67ac84 initial\n>     * topic     3fc0f2a [topicbase: broken] topic\n\nI'd assume this is s/broken/gone/ to match what the rest of the log\nmessage says?\n\n>     $ git status\n>     # On branch topic\n>     # Your branch is based on a broken ref 'topicbase'.\n>     #   (use \"git branch --unset-upstream\" to fixup)\n>     ...\n>\n>     $ git status -b -s\n>     ## topic...topicbase [broken]\n>     ...\n>\n> In order to do like that, we need to distinguish these three cases\n> (i.e. no tracking, with configured but no longer valid tracking, and\n> with tracking) in function stat_tracking_info(). So the refactored\n> function stat_tracking_info() has three return values: -1 (with \"gone\"\n> base), 0 (no base), and 1 (with base).\n"},{"id":"225299","messageId":"7vzjsio99d.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"8db143908bc969bbe1d720479fb6214729f7b1ae.1376590264.git.worldhello.net@gmail.com","subject":"Re: [PATCH v6 2/3] branch: report invalid tracking branch as broken","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-15T22:54:22Z","receivedAt":"2013-08-15T22:54:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n>  /*\n> - * Return false if cannot stat a tracking branch (not exist or invalid),\n> - * otherwise true.\n> + * Compare a branch with its tracking branch, and save their differences\n> + * (number of commits) in *num_ours and *num_theirs.\n> + *\n> + * Return 0 if branch has no upstream, -1 if upstream is missing or invalid,\n> + * otherwise 1.\n>   */\n\nWhat is the difference between a branch that has no upstream and\nupstream being missing?  Or between missing and invalid?\n\nI think you are trying to say the difference between\n\"branch.<name>.merge is not set at all\" and \"branch.<name>.merge is\nin the configuration, but the named upstream ref does not exist\".\n\nYou are calling the latter \"missing or invalid\", but how does one\ntell missing ones from invalid ones?  I think there isn't a\ndistinction, so it would be better to just say \"missing\" (or \"gone\",\nwhich is very much more likely reason why you still have\nconfiguration without a ref).\n\nI am not sure it is a good idea to label \"missing\" as \"broken\" or\n\"invalid\", but it seems that your tests, in code comments and\nvariable names are full of these negative connotations.\n\nHmph...\n"},{"id":"225300","messageId":"7vvc36o95m.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"224af6e4fce9004aa50ea0c11c703107857c46f0.1376590264.git.worldhello.net@gmail.com","subject":"Re: [PATCH v6 3/3] status: always show tracking branch even no change","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-15T22:56:37Z","receivedAt":"2013-08-15T22:56:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> In order to see what the current branch is tracking, one way is using\n> \"git branch -v -v\", but branches other than the current are also\n> reported. Another way is using \"git status\", such as:\n>\n>     $ git status\n>     # On branch master\n>     # Your branch is ahead of 'origin/master' by 1 commit.\n>     ...\n>\n> But this will not work if there is no change between the current\n> branch and its upstream. What if report upstream tracking info\n> always even if there is no difference. E.g.\n>\n>     $ git status\n>     # On branch feature1\n>     # Your branch is identical to 'github/feature1'.\n>     ...\n>\n>     $ git status -bs\n>     ## feature1...github/feature1\n>     ...\n>\n>     $ git checkout feature1\n>     Already on 'feature1'\n>     Your branch is identical to 'github/feature1'.\n>     ...\n\nThe sentence that began with \"What if ...\" never completed?\n"},{"id":"225306","messageId":"cover.1376618877.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"7vzjsio99d.fsf@alter.siamese.dyndns.org","subject":"[PATCH v7 0/3] some enhancements for reporting branch tracking info","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-16T02:29:31Z","receivedAt":"2013-08-16T02:29:31Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Changes since v6:\n\n* s/broken/gone/ in [PATCH 2/3] (branch: mark missing tracking branch\n  as gone)\n\n* rewrite commit log for [PATCH 3/3] (status: always show tracking\n  branch even no change)\n\nJiang Xin (3):\n  branch: not report invalid tracking branch\n  branch: mark missing tracking branch as gone\n  status: always show tracking branch even no change\n\n builtin/branch.c         | 36 ++++++++++++--------\n remote.c                 | 72 +++++++++++++++++++++++++--------------\n t/t6040-tracking-info.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++---\n wt-status.c              | 26 +++++++++++---\n 4 files changed, 175 insertions(+), 48 deletions(-)\n\n-- \n1.8.4.rc2.479.g44abce8\n"},{"id":"225308","messageId":"6bc0643a5fa0fae03be6fdb59f63075be1e4d983.1376620130.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"cover.1376618877.git.worldhello.net@gmail.com","subject":"[PATCH v7 1/3] branch: not report invalid tracking branch","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-16T02:29:32Z","receivedAt":"2013-08-16T02:29:32Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Command \"git branch -vv\" will report tracking branches, but invalid\ntracking branches are also reported. This is because the function\nstat_tracking_info() can not distinguish whether the upstream branch\ndoes not exist, or nothing is changed between one branch and its\nupstream.\n\nThis patch changes the return value of function stat_tracking_info().\nOnly returns false when there is no tracking branch or the tracking\nbranch is invalid, otherwise true. If the caller does not like to\nreport tracking info when nothing changed between the branch and its\nupstream, simply checks if num_theirs and num_ours are both 0.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/branch.c         | 24 ++++++++----------------\n remote.c                 | 43 ++++++++++++++++++++++---------------------\n t/t6040-tracking-info.sh |  8 ++++++--\n wt-status.c              | 13 +++++++++++--\n 4 files changed, 47 insertions(+), 41 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0903763..3e016a6 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -424,19 +424,8 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n-\t\t    show_upstream_ref) {\n-\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\t\tif (want_color(branch_use_color))\n-\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\t\telse\n-\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n-\t\t}\n+\tif (!stat_tracking_info(branch, &ours, &theirs))\n \t\treturn;\n-\t}\n \n \tif (show_upstream_ref) {\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n@@ -448,19 +437,22 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours) {\n-\t\tif (ref)\n+\tif (!ours && !theirs) {\n+\t\tif (show_upstream_ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n+\t} else if (!ours) {\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n \t\telse\n \t\t\tstrbuf_addf(stat, _(\"[behind %d]\"), theirs);\n \n \t} else if (!theirs) {\n-\t\tif (ref)\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d]\"), fancy.buf, ours);\n \t\telse\n \t\t\tstrbuf_addf(stat, _(\"[ahead %d]\"), ours);\n \t} else {\n-\t\tif (ref)\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d, behind %d]\"),\n \t\t\t\t    fancy.buf, ours, theirs);\n \t\telse\ndiff --git a/remote.c b/remote.c\nindex 2433467..26bd543 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1729,7 +1729,8 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n }\n \n /*\n- * Return true if there is anything to report, otherwise false.\n+ * Return false if cannot stat a tracking branch (not exist or invalid),\n+ * otherwise true.\n  */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n {\n@@ -1740,18 +1741,12 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n-\t/*\n-\t * Nothing to report unless we are marked to build on top of\n-\t * somebody else.\n-\t */\n+\t/* Cannot stat unless we are marked to build on top of somebody else. */\n \tif (!branch ||\n \t    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)\n \t\treturn 0;\n \n-\t/*\n-\t * If what we used to build on no longer exists, there is\n-\t * nothing to report.\n-\t */\n+\t/* Cannot stat if what we used to build on no longer exists */\n \tbase = branch->merge[0]->dst;\n \tif (read_ref(base, sha1))\n \t\treturn 0;\n@@ -1766,8 +1761,10 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \t\treturn 0;\n \n \t/* are we the same? */\n-\tif (theirs == ours)\n-\t\treturn 0;\n+\tif (theirs == ours) {\n+\t\t*num_theirs = *num_ours = 0;\n+\t\treturn 1;\n+\t}\n \n \t/* Run \"rev-list --left-right ours...theirs\" internally... */\n \trev_argc = 0;\n@@ -1809,31 +1806,35 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n  */\n int format_tracking_info(struct branch *branch, struct strbuf *sb)\n {\n-\tint num_ours, num_theirs;\n+\tint ours, theirs;\n \tconst char *base;\n \n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n+\tif (!stat_tracking_info(branch, &ours, &theirs))\n+\t\treturn 0;\n+\n+\t/* Nothing to report if neither side has changes. */\n+\tif (!ours && !theirs)\n \t\treturn 0;\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\n-\t\t\t   num_ours),\n-\t\t\tbase, num_ours);\n+\t\t\t   ours),\n+\t\t\tbase, ours);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git push\\\" to publish your local commits)\\n\"));\n-\t} else if (!num_ours) {\n+\t} else if (!ours) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is behind '%s' by %d commit, \"\n \t\t\t       \"and can be fast-forwarded.\\n\",\n \t\t\t   \"Your branch is behind '%s' by %d commits, \"\n \t\t\t       \"and can be fast-forwarded.\\n\",\n-\t\t\t   num_theirs),\n-\t\t\tbase, num_theirs);\n+\t\t\t   theirs),\n+\t\t\tbase, theirs);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git pull\\\" to update your local branch)\\n\"));\n@@ -1845,8 +1846,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\t\t   \"Your branch and '%s' have diverged,\\n\"\n \t\t\t       \"and have %d and %d different commits each, \"\n \t\t\t       \"respectively.\\n\",\n-\t\t\t   num_theirs),\n-\t\t\tbase, num_ours, num_theirs);\n+\t\t\t   theirs),\n+\t\t\tbase, ours, theirs);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git pull\\\" to merge the remote branch into yours)\\n\"));\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..471dd64 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -28,10 +28,14 @@ test_expect_success setup '\n \t\tgit reset --hard HEAD^ &&\n \t\tgit checkout -b b4 origin &&\n \t\tadvance e &&\n-\t\tadvance f\n+\t\tadvance f &&\n+\t\tgit checkout -b brokenbase origin &&\n+\t\tgit checkout -b b5 --track brokenbase &&\n+\t\tadvance g &&\n+\t\tgit branch -d brokenbase\n \t) &&\n \tgit checkout -b follower --track master &&\n-\tadvance g\n+\tadvance h\n '\n \n script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\ndiff --git a/wt-status.c b/wt-status.c\nindex ff4b324..0c6a3a5 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1380,15 +1380,24 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tbranch = branch_get(s->branch + 11);\n \tif (s->is_initial)\n \t\tcolor_fprintf(s->fp, header_color, _(\"Initial commit on \"));\n+\n+\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\n+\t/*\n+\t * Not report tracking info if no tracking branch found\n+\t * or no difference found.\n+\t */\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\tif (!num_ours && !num_theirs) {\n \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n \t\treturn;\n \t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n-- \n1.8.4.rc2.479.g44abce8\n"},{"id":"225307","messageId":"a4b446b4ff63f56f8203df0723eeb319b2ba58dc.1376620130.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"cover.1376618877.git.worldhello.net@gmail.com","subject":"[PATCH v7 2/3] branch: mark missing tracking branch as gone","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-16T02:29:33Z","receivedAt":"2013-08-16T02:29:33Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"If a branch has been set to track a upstream, but the upstream branch\nis missing, the tracking info is silently ignored in the output of\nsome commands such as \"git branch -vv\" and \"git status\", as if there\nwere no such tracking settings.\n\nJunio suggested missing upstream should be reported [1], such as:\n\n    $ git branch -v -v\n      master    e67ac84 initial\n    * topic     3fc0f2a [topicbase: gone] topic\n\n    $ git status\n    # On branch topic\n    # Your branch is based on 'topicbase', but the upstream is gone.\n    #   (use \"git branch --unset-upstream\" to fixup)\n    ...\n\n    $ git status -b -s\n    ## topic...topicbase [gone]\n    ...\n\nIn order to do like that, we need to distinguish these three cases\n(i.e. no tracking, with configured but no longer valid tracking, and\nwith tracking) in function stat_tracking_info(). So the refactored\nfunction stat_tracking_info() has three return values: -1 (with \"gone\"\nbase), 0 (no base), and 1 (with base).\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/231830/focus=232288\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n builtin/branch.c         | 18 ++++++++++++++++--\n remote.c                 | 44 +++++++++++++++++++++++++++++++------------\n t/t6040-tracking-info.sh | 49 ++++++++++++++++++++++++++++++++++++++++++++++--\n wt-status.c              | 28 +++++++++++++++++----------\n 4 files changed, 113 insertions(+), 26 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 3e016a6..ad0f86d 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -423,9 +423,20 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tchar *ref = NULL;\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n+\tint upstream_is_gone = 0;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs))\n+\tswitch (stat_tracking_info(branch, &ours, &theirs)) {\n+\tcase 0:\n+\t\t/* no base */\n \t\treturn;\n+\tcase -1:\n+\t\t/* with \"gone\" base */\n+\t\tupstream_is_gone = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* with base */\n+\t\tbreak;\n+\t}\n \n \tif (show_upstream_ref) {\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n@@ -437,7 +448,10 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours && !theirs) {\n+\tif (upstream_is_gone) {\n+\t\tif (show_upstream_ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s: gone]\"), fancy.buf);\n+\t} else if (!ours && !theirs) {\n \t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n \t} else if (!ours) {\ndiff --git a/remote.c b/remote.c\nindex 26bd543..4caccb5 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1729,8 +1729,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n }\n \n /*\n- * Return false if cannot stat a tracking branch (not exist or invalid),\n- * otherwise true.\n+ * Compare a branch with its upstream, and save their differences (number\n+ * of commits) in *num_ours and *num_theirs.\n+ *\n+ * Return 0 if branch has no upstream (no base), -1 if upstream is missing\n+ * (with \"gone\" base), otherwise 1 (with base).\n  */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n {\n@@ -1749,16 +1752,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \t/* Cannot stat if what we used to build on no longer exists */\n \tbase = branch->merge[0]->dst;\n \tif (read_ref(base, sha1))\n-\t\treturn 0;\n+\t\treturn -1;\n \ttheirs = lookup_commit_reference(sha1);\n \tif (!theirs)\n-\t\treturn 0;\n+\t\treturn -1;\n \n \tif (read_ref(branch->refname, sha1))\n-\t\treturn 0;\n+\t\treturn -1;\n \tours = lookup_commit_reference(sha1);\n \tif (!ours)\n-\t\treturn 0;\n+\t\treturn -1;\n \n \t/* are we the same? */\n \tif (theirs == ours) {\n@@ -1808,17 +1811,34 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n {\n \tint ours, theirs;\n \tconst char *base;\n+\tint upstream_is_gone = 0;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs))\n-\t\treturn 0;\n-\n-\t/* Nothing to report if neither side has changes. */\n-\tif (!ours && !theirs)\n+\tswitch (stat_tracking_info(branch, &ours, &theirs)) {\n+\tcase 0:\n+\t\t/* no base */\n \t\treturn 0;\n+\tcase -1:\n+\t\t/* with \"gone\" base */\n+\t\tupstream_is_gone = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* Nothing to report if neither side has changes. */\n+\t\tif (!ours && !theirs)\n+\t\t\treturn 0;\n+\t\t/* with base */\n+\t\tbreak;\n+\t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!theirs) {\n+\tif (upstream_is_gone) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is based on '%s', but the upstream is gone.\\n\"),\n+\t\t\tbase);\n+\t\tif (advice_status_hints)\n+\t\t\tstrbuf_addf(sb,\n+\t\t\t\t_(\"  (use \\\"git branch --unset-upstream\\\" to fixup)\\n\"));\n+\t} else if (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 471dd64..6f678a4 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -60,6 +60,7 @@ b1 origin/master: ahead 1, behind 1\n b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n+b5 brokenbase: gone\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -71,7 +72,7 @@ test_expect_success 'branch -vv' '\n \ttest_i18ncmp expect actual\n '\n \n-test_expect_success 'checkout' '\n+test_expect_success 'checkout (diverged from upstream)' '\n \t(\n \t\tcd test && git checkout b1\n \t) >actual &&\n@@ -84,7 +85,15 @@ test_expect_success 'checkout with local tracked branch' '\n \ttest_i18ngrep \"is ahead of\" actual\n '\n \n-test_expect_success 'status' '\n+test_expect_success 'checkout (upstream is gone)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5\n+\t) >actual &&\n+\ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n+'\n+\n+test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n \t\tgit checkout b1 >/dev/null &&\n@@ -94,6 +103,42 @@ test_expect_success 'status' '\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'status (upstream is gone)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n+'\n+\n+cat >expect <<\\EOF\n+## b1...origin/master [ahead 1, behind 1]\n+EOF\n+\n+test_expect_success 'status -s -b (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+## b5...brokenbase [gone]\n+EOF\n+\n+test_expect_success 'status -s -b (upstream is gone)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 0c6a3a5..46d181a 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1363,6 +1363,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tconst char *base;\n \tconst char *branch_name;\n \tint num_ours, num_theirs;\n+\tint upstream_is_gone = 0;\n \n \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"## \");\n \n@@ -1383,17 +1384,22 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \n \tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \n-\t/*\n-\t * Not report tracking info if no tracking branch found\n-\t * or no difference found.\n-\t */\n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\treturn;\n-\t}\n-\tif (!num_ours && !num_theirs) {\n+\tswitch (stat_tracking_info(branch, &num_ours, &num_theirs)) {\n+\tcase 0:\n+\t\t/* no base */\n \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n \t\treturn;\n+\tcase -1:\n+\t\t/* with \"gone\" base */\n+\t\tupstream_is_gone = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* with base */\n+\t\tif (!num_ours && !num_theirs) {\n+\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\t\treturn;\n+\t\t}\n+\t\tbreak;\n \t}\n \n \tbase = branch->merge[0]->dst;\n@@ -1402,7 +1408,9 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n \tcolor_fprintf(s->fp, header_color, \" [\");\n-\tif (!num_ours) {\n+\tif (upstream_is_gone) {\n+\t\tcolor_fprintf(s->fp, header_color, _(\"gone\"));\n+\t} else if (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n \t\tcolor_fprintf(s->fp, branch_color_remote, \"%d\", num_theirs);\n \t} else if (!num_theirs) {\n-- \n1.8.4.rc2.479.g44abce8\n"},{"id":"225309","messageId":"83686ec4894d881b3dd6272fd235762146ae5111.1376620130.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"cover.1376618877.git.worldhello.net@gmail.com","subject":"[PATCH v7 3/3] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-16T02:29:34Z","receivedAt":"2013-08-16T02:29:34Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"In order to see what the current branch is tracking, one way is using\n\"git branch -v -v\", but branches other than the current are also\nreported. Another way is using \"git status\", such as:\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    ...\n\nBut this will not work if there is no change between the current\nbranch and its upstream. Always report upstream tracking info\neven if there is no difference, so that \"git status\" is consistent\nfor checking tracking info for current branch. E.g.\n\n    $ git status\n    # On branch feature1\n    # Your branch is identical to 'github/feature1'.\n    ...\n\n    $ git status -bs\n    ## feature1...github/feature1\n    ...\n\n    $ git checkout feature1\n    Already on 'feature1'\n    Your branch is identical to 'github/feature1'.\n    ...\n\nAlso add some test cases in t6040.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\n---\n remote.c                 |  7 ++++---\n t/t6040-tracking-info.sh | 34 +++++++++++++++++++++++++++++++++-\n wt-status.c              |  9 +++++----\n 3 files changed, 42 insertions(+), 8 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 4caccb5..79effe6 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1822,9 +1822,6 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\tupstream_is_gone = 1;\n \t\tbreak;\n \tdefault:\n-\t\t/* Nothing to report if neither side has changes. */\n-\t\tif (!ours && !theirs)\n-\t\t\treturn 0;\n \t\t/* with base */\n \t\tbreak;\n \t}\n@@ -1838,6 +1835,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git branch --unset-upstream\\\" to fixup)\\n\"));\n+\t} else if (!ours && !theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to '%s'.\\n\"),\n+\t\t\tbase);\n \t} else if (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 6f678a4..b24a18c 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -32,7 +32,8 @@ test_expect_success setup '\n \t\tgit checkout -b brokenbase origin &&\n \t\tgit checkout -b b5 --track brokenbase &&\n \t\tadvance g &&\n-\t\tgit branch -d brokenbase\n+\t\tgit branch -d brokenbase &&\n+\t\tgit checkout -b b6 origin\n \t) &&\n \tgit checkout -b follower --track master &&\n \tadvance h\n@@ -61,6 +62,7 @@ b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n b5 brokenbase: gone\n+b6 origin/master\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -93,6 +95,13 @@ test_expect_success 'checkout (upstream is gone)' '\n \ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n '\n \n+test_expect_success 'checkout (identical to upstream)' '\n+\t(\n+\t\tcd test && git checkout b6\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n@@ -113,6 +122,16 @@ test_expect_success 'status (upstream is gone)' '\n \ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n '\n \n+test_expect_success 'status (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b6 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n cat >expect <<\\EOF\n ## b1...origin/master [ahead 1, behind 1]\n EOF\n@@ -139,6 +158,19 @@ test_expect_success 'status -s -b (upstream is gone)' '\n \ttest_i18ncmp expect actual\n '\n \n+cat >expect <<\\EOF\n+## b6...origin/master\n+EOF\n+\n+test_expect_success 'status -s -b (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b6 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 46d181a..c8c2d77 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1395,10 +1395,6 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \t\tbreak;\n \tdefault:\n \t\t/* with base */\n-\t\tif (!num_ours && !num_theirs) {\n-\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\t\treturn;\n-\t\t}\n \t\tbreak;\n \t}\n \n@@ -1407,6 +1403,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!upstream_is_gone && !num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (upstream_is_gone) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"gone\"));\n-- \n1.8.4.rc2.479.g44abce8\n"},{"id":"225426","messageId":"7v7gfiojz7.fsf@alter.siamese.dyndns.org","threadId":"34633","inReplyTo":"cover.1376618877.git.worldhello.net@gmail.com","subject":"Re: [PATCH v7 0/3] some enhancements for reporting branch tracking info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-18T19:51:56Z","receivedAt":"2013-08-18T19:51:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> Changes since v6:\n>\n> * s/broken/gone/ in [PATCH 2/3] (branch: mark missing tracking branch\n>   as gone)\n>\n> * rewrite commit log for [PATCH 3/3] (status: always show tracking\n>   branch even no change)\n>\n> Jiang Xin (3):\n>   branch: not report invalid tracking branch\n>   branch: mark missing tracking branch as gone\n>   status: always show tracking branch even no change\n>\n>  builtin/branch.c         | 36 ++++++++++++--------\n>  remote.c                 | 72 +++++++++++++++++++++++++--------------\n>  t/t6040-tracking-info.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++---\n>  wt-status.c              | 26 +++++++++++---\n>  4 files changed, 175 insertions(+), 48 deletions(-)\n\nThanks; getting clearer to read.\n\nI however feel that [1/3] is introducing a regression (what we used\nto report, gone branches, are hidden), only to correct the\nregression immediately after it with [2/3].\n\nI wonder if these patches should be combined into one, with\njustification like \"with the current code, a branch that is in sync\nwith its upstream, a branch whose upstream no longer exists and a\nbranch that does not build on anything else cannot be distinguished;\nshow the first class as 'same', mark the second class as 'gone', and\nshow only the last one as not having any uptream', or something.\n"},{"id":"225439","messageId":"CANYiYbEtWF3m_ACActD2TDjhXh_=1qJ07Rgc3mb8Nfgogjh-RQ@mail.gmail.com","threadId":"34633","inReplyTo":"7v7gfiojz7.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v7 0/3] some enhancements for reporting branch tracking info","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-19T00:38:55Z","receivedAt":"2013-08-19T00:38:55Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"2013/8/19 Junio C Hamano <gitster@pobox.com>:\n>\n> I however feel that [1/3] is introducing a regression (what we used\n> to report, gone branches, are hidden), only to correct the\n> regression immediately after it with [2/3].\n>\n> I wonder if these patches should be combined into one\n\nYes, at least patch 1/3 and patch 2/3 can be squashed into one.\n\n> justification like \"with the current code, a branch that is in sync\n> with its upstream, a branch whose upstream no longer exists and a\n> branch that does not build on anything else cannot be distinguished;\n> show the first class as 'same', mark the second class as 'gone', and\n\nFor the first class, if there are differences between branch and\nits upstream, tracking info is displayed, but report nothing if they\nare identical. I do think report something in this case is useful.\nIt may help me to find out which remote I am tracking, if there are\nseveral remotes for my repo.\n\n> show only the last one as 'not having any uptream', or something.\n\nI think keep silence in this case is better.\n\n-- \nJiang Xin\n"},{"id":"225601","messageId":"vpqeh9nh4u7.fsf@anie.imag.fr","threadId":"34633","inReplyTo":"a4b446b4ff63f56f8203df0723eeb319b2ba58dc.1376620130.git.worldhello.net@gmail.com","subject":"Re: [PATCH v7 2/3] branch: mark missing tracking branch as gone","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2013-08-21T07:37:36Z","receivedAt":"2013-08-21T07:37:36Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n>     $ git status\n>     # On branch topic\n>     # Your branch is based on 'topicbase', but the upstream is gone.\n>     #   (use \"git branch --unset-upstream\" to fixup)\n\nSorry, I didn't follow closely the previous discussions. I'm not sure\n\"gone\" is right either, since the user may just have configured an\nupstream that does not exist and never existed. Perhaps \"absent\" would\nbe better.\n\nJust a thought, shouldn't block the patch.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"225663","messageId":"CANYiYbEewHBTvmeZbfQXj-36aujjtrABzc=2fT1dgA-rJmDynw@mail.gmail.com","threadId":"34633","inReplyTo":"vpqeh9nh4u7.fsf@anie.imag.fr","subject":"Re: [PATCH v7 2/3] branch: mark missing tracking branch as gone","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-22T00:00:53Z","receivedAt":"2013-08-22T00:00:53Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"2013/8/21 Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>:\n> Jiang Xin <worldhello.net@gmail.com> writes:\n>\n>>     $ git status\n>>     # On branch topic\n>>     # Your branch is based on 'topicbase', but the upstream is gone.\n>>     #   (use \"git branch --unset-upstream\" to fixup)\n>\n> Sorry, I didn't follow closely the previous discussions. I'm not sure\n> \"gone\" is right either, since the user may just have configured an\n> upstream that does not exist and never existed. Perhaps \"absent\" would\n> be better.\n>\n> Just a thought, shouldn't block the patch.\n\nThank you for following this, and offering better statements. I will\nmake another reroll after the end of my business trip this week.\n\n-- \nJiang Xin\n"},{"id":"225883","messageId":"cover.1377500206.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"7v7gfiojz7.fsf@alter.siamese.dyndns.org","subject":"[PATCH v8 0/2] some enhancements for reporting branch tracking info","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-26T07:02:47Z","receivedAt":"2013-08-26T07:02:47Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Changes since v7:\n\n* Squashed patch 1/3 and patch 2/3 into one big patch.\n\nBut not s/gone/absent/ as Matthieu suggested.\n\nJiang Xin (2):\n  branch: report invalid tracking branch as gone\n  status: always show tracking branch even no change\n\n builtin/branch.c         | 36 ++++++++++++--------\n remote.c                 | 72 +++++++++++++++++++++++++--------------\n t/t6040-tracking-info.sh | 89 +++++++++++++++++++++++++++++++++++++++++++++---\n wt-status.c              | 26 +++++++++++---\n 4 files changed, 175 insertions(+), 48 deletions(-)\n\n-- \n1.8.4.rc3.2.g434fd97\n"},{"id":"225884","messageId":"5b4a10dc41db70c225dc1dfd840b509b73b3dad7.1377500206.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"cover.1377500206.git.worldhello.net@gmail.com","subject":"[PATCH v8 1/2] branch: report invalid tracking branch as gone","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-26T07:02:48Z","receivedAt":"2013-08-26T07:02:48Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"Command \"git branch -vv\" will report tracking branches, but invalid\ntracking branches are also reported. This is because the function\nstat_tracking_info() can not distinguish invalid tracking branch\nfrom other cases which it would not like to report, such as\nthere is no upstream settings at all, or nothing is changed between\none branch and its upstream.\n\nJunio suggested missing upstream should be reported [1] like:\n\n    $ git branch -v -v\n      master    e67ac84 initial\n    * topic     3fc0f2a [topicbase: gone] topic\n\n    $ git status\n    # On branch topic\n    # Your branch is based on 'topicbase', but the upstream is gone.\n    #   (use \"git branch --unset-upstream\" to fixup)\n    ...\n\n    $ git status -b -s\n    ## topic...topicbase [gone]\n    ...\n\nIn order to do like that, we need to distinguish these three cases\n(i.e. no tracking, with configured but no longer valid tracking, and\nwith tracking) in function stat_tracking_info(). So the refactored\nfunction stat_tracking_info() has three return values: -1 (with \"gone\"\nbase), 0 (no base), and 1 (with base).\n\nIf the caller does not like to report tracking info when nothing\nchanged between the branch and its upstream, simply checks if\nnum_theirs and num_ours are both 0.\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/231830/focus=232288\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/branch.c         | 36 ++++++++++++++----------\n remote.c                 | 71 +++++++++++++++++++++++++++++++-----------------\n t/t6040-tracking-info.sh | 57 +++++++++++++++++++++++++++++++++++---\n wt-status.c              | 26 +++++++++++++++---\n 4 files changed, 142 insertions(+), 48 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0836890..0539fda 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -423,19 +423,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tchar *ref = NULL;\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n+\tint upstream_is_gone = 0;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n-\t\t    show_upstream_ref) {\n-\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\t\tif (want_color(branch_use_color))\n-\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\t\telse\n-\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n-\t\t}\n+\tswitch (stat_tracking_info(branch, &ours, &theirs)) {\n+\tcase 0:\n+\t\t/* no base */\n \t\treturn;\n+\tcase -1:\n+\t\t/* with \"gone\" base */\n+\t\tupstream_is_gone = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* with base */\n+\t\tbreak;\n \t}\n \n \tif (show_upstream_ref) {\n@@ -448,19 +448,25 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\tstrbuf_addstr(&fancy, ref);\n \t}\n \n-\tif (!ours) {\n-\t\tif (ref)\n+\tif (upstream_is_gone) {\n+\t\tif (show_upstream_ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s: gone]\"), fancy.buf);\n+\t} else if (!ours && !theirs) {\n+\t\tif (show_upstream_ref)\n+\t\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n+\t} else if (!ours) {\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: behind %d]\"), fancy.buf, theirs);\n \t\telse\n \t\t\tstrbuf_addf(stat, _(\"[behind %d]\"), theirs);\n \n \t} else if (!theirs) {\n-\t\tif (ref)\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d]\"), fancy.buf, ours);\n \t\telse\n \t\t\tstrbuf_addf(stat, _(\"[ahead %d]\"), ours);\n \t} else {\n-\t\tif (ref)\n+\t\tif (show_upstream_ref)\n \t\t\tstrbuf_addf(stat, _(\"[%s: ahead %d, behind %d]\"),\n \t\t\t\t    fancy.buf, ours, theirs);\n \t\telse\ndiff --git a/remote.c b/remote.c\nindex efcba93..87c8dd3 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1695,7 +1695,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n }\n \n /*\n- * Return true if there is anything to report, otherwise false.\n+ * Compare a branch with its upstream, and save their differences (number\n+ * of commits) in *num_ours and *num_theirs.\n+ *\n+ * Return 0 if branch has no upstream (no base), -1 if upstream is missing\n+ * (with \"gone\" base), otherwise 1 (with base).\n  */\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n {\n@@ -1706,34 +1710,30 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \tconst char *rev_argv[10], *base;\n \tint rev_argc;\n \n-\t/*\n-\t * Nothing to report unless we are marked to build on top of\n-\t * somebody else.\n-\t */\n+\t/* Cannot stat unless we are marked to build on top of somebody else. */\n \tif (!branch ||\n \t    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)\n \t\treturn 0;\n \n-\t/*\n-\t * If what we used to build on no longer exists, there is\n-\t * nothing to report.\n-\t */\n+\t/* Cannot stat if what we used to build on no longer exists */\n \tbase = branch->merge[0]->dst;\n \tif (read_ref(base, sha1))\n-\t\treturn 0;\n+\t\treturn -1;\n \ttheirs = lookup_commit_reference(sha1);\n \tif (!theirs)\n-\t\treturn 0;\n+\t\treturn -1;\n \n \tif (read_ref(branch->refname, sha1))\n-\t\treturn 0;\n+\t\treturn -1;\n \tours = lookup_commit_reference(sha1);\n \tif (!ours)\n-\t\treturn 0;\n+\t\treturn -1;\n \n \t/* are we the same? */\n-\tif (theirs == ours)\n-\t\treturn 0;\n+\tif (theirs == ours) {\n+\t\t*num_theirs = *num_ours = 0;\n+\t\treturn 1;\n+\t}\n \n \t/* Run \"rev-list --left-right ours...theirs\" internally... */\n \trev_argc = 0;\n@@ -1775,31 +1775,52 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n  */\n int format_tracking_info(struct branch *branch, struct strbuf *sb)\n {\n-\tint num_ours, num_theirs;\n+\tint ours, theirs;\n \tconst char *base;\n+\tint upstream_is_gone = 0;\n \n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n+\tswitch (stat_tracking_info(branch, &ours, &theirs)) {\n+\tcase 0:\n+\t\t/* no base */\n \t\treturn 0;\n+\tcase -1:\n+\t\t/* with \"gone\" base */\n+\t\tupstream_is_gone = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* Nothing to report if neither side has changes. */\n+\t\tif (!ours && !theirs)\n+\t\t\treturn 0;\n+\t\t/* with base */\n+\t\tbreak;\n+\t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tif (!num_theirs) {\n+\tif (upstream_is_gone) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is based on '%s', but the upstream is gone.\\n\"),\n+\t\t\tbase);\n+\t\tif (advice_status_hints)\n+\t\t\tstrbuf_addf(sb,\n+\t\t\t\t_(\"  (use \\\"git branch --unset-upstream\\\" to fixup)\\n\"));\n+\t} else if (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\n \t\t\t   \"Your branch is ahead of '%s' by %d commits.\\n\",\n-\t\t\t   num_ours),\n-\t\t\tbase, num_ours);\n+\t\t\t   ours),\n+\t\t\tbase, ours);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git push\\\" to publish your local commits)\\n\"));\n-\t} else if (!num_ours) {\n+\t} else if (!ours) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is behind '%s' by %d commit, \"\n \t\t\t       \"and can be fast-forwarded.\\n\",\n \t\t\t   \"Your branch is behind '%s' by %d commits, \"\n \t\t\t       \"and can be fast-forwarded.\\n\",\n-\t\t\t   num_theirs),\n-\t\t\tbase, num_theirs);\n+\t\t\t   theirs),\n+\t\t\tbase, theirs);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git pull\\\" to update your local branch)\\n\"));\n@@ -1811,8 +1832,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\t\t   \"Your branch and '%s' have diverged,\\n\"\n \t\t\t       \"and have %d and %d different commits each, \"\n \t\t\t       \"respectively.\\n\",\n-\t\t\t   num_theirs),\n-\t\t\tbase, num_ours, num_theirs);\n+\t\t\t   theirs),\n+\t\t\tbase, ours, theirs);\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git pull\\\" to merge the remote branch into yours)\\n\"));\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..6f678a4 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -28,10 +28,14 @@ test_expect_success setup '\n \t\tgit reset --hard HEAD^ &&\n \t\tgit checkout -b b4 origin &&\n \t\tadvance e &&\n-\t\tadvance f\n+\t\tadvance f &&\n+\t\tgit checkout -b brokenbase origin &&\n+\t\tgit checkout -b b5 --track brokenbase &&\n+\t\tadvance g &&\n+\t\tgit branch -d brokenbase\n \t) &&\n \tgit checkout -b follower --track master &&\n-\tadvance g\n+\tadvance h\n '\n \n script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\n@@ -56,6 +60,7 @@ b1 origin/master: ahead 1, behind 1\n b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n+b5 brokenbase: gone\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -67,7 +72,7 @@ test_expect_success 'branch -vv' '\n \ttest_i18ncmp expect actual\n '\n \n-test_expect_success 'checkout' '\n+test_expect_success 'checkout (diverged from upstream)' '\n \t(\n \t\tcd test && git checkout b1\n \t) >actual &&\n@@ -80,7 +85,15 @@ test_expect_success 'checkout with local tracked branch' '\n \ttest_i18ngrep \"is ahead of\" actual\n '\n \n-test_expect_success 'status' '\n+test_expect_success 'checkout (upstream is gone)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5\n+\t) >actual &&\n+\ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n+'\n+\n+test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n \t\tgit checkout b1 >/dev/null &&\n@@ -90,6 +103,42 @@ test_expect_success 'status' '\n \ttest_i18ngrep \"have 1 and 1 different\" actual\n '\n \n+test_expect_success 'status (upstream is gone)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n+'\n+\n+cat >expect <<\\EOF\n+## b1...origin/master [ahead 1, behind 1]\n+EOF\n+\n+test_expect_success 'status -s -b (diverged from upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b1 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n+## b5...brokenbase [gone]\n+EOF\n+\n+test_expect_success 'status -s -b (upstream is gone)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b5 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex cb24f1f..4b1713e 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1365,6 +1365,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tconst char *base;\n \tconst char *branch_name;\n \tint num_ours, num_theirs;\n+\tint upstream_is_gone = 0;\n \n \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER, s), \"## \");\n \n@@ -1382,20 +1383,37 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tbranch = branch_get(s->branch + 11);\n \tif (s->is_initial)\n \t\tcolor_fprintf(s->fp, header_color, _(\"Initial commit on \"));\n-\tif (!stat_tracking_info(branch, &num_ours, &num_theirs)) {\n-\t\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\n+\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n+\n+\tswitch (stat_tracking_info(branch, &num_ours, &num_theirs)) {\n+\tcase 0:\n+\t\t/* no base */\n \t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n \t\treturn;\n+\tcase -1:\n+\t\t/* with \"gone\" base */\n+\t\tupstream_is_gone = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* Stop reporting if neither side has changes. */\n+\t\tif (!num_ours && !num_theirs) {\n+\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\t\treturn;\n+\t\t}\n+\t\t/* with base */\n+\t\tbreak;\n \t}\n \n \tbase = branch->merge[0]->dst;\n \tbase = shorten_unambiguous_ref(base, 0);\n-\tcolor_fprintf(s->fp, branch_color_local, \"%s\", branch_name);\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n \tcolor_fprintf(s->fp, header_color, \" [\");\n-\tif (!num_ours) {\n+\tif (upstream_is_gone) {\n+\t\tcolor_fprintf(s->fp, header_color, _(\"gone\"));\n+\t} else if (!num_ours) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"behind \"));\n \t\tcolor_fprintf(s->fp, branch_color_remote, \"%d\", num_theirs);\n \t} else if (!num_theirs) {\n-- \n1.8.4.rc3.2.g434fd97\n"},{"id":"225885","messageId":"2f3a942d7049e80dca689aa68d494b70c288f2c7.1377500206.git.worldhello.net@gmail.com","threadId":"34633","inReplyTo":"cover.1377500206.git.worldhello.net@gmail.com","subject":"[PATCH v8 2/2] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-26T07:02:49Z","receivedAt":"2013-08-26T07:02:49Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"In order to see what the current branch is tracking, one way is using\n\"git branch -v -v\", but branches other than the current are also\nreported. Another way is using \"git status\", such as:\n\n    $ git status\n    # On branch master\n    # Your branch is ahead of 'origin/master' by 1 commit.\n    ...\n\nBut this will not work if there is no change between the current\nbranch and its upstream. Always report upstream tracking info\neven if there is no difference, so that \"git status\" is consistent\nfor checking tracking info for current branch. E.g.\n\n    $ git status\n    # On branch feature1\n    # Your branch is identical to 'github/feature1'.\n    ...\n\n    $ git status -bs\n    ## feature1...github/feature1\n    ...\n\n    $ git checkout feature1\n    Already on 'feature1'\n    Your branch is identical to 'github/feature1'.\n    ...\n\nAlso add some test cases in t6040.\n\nSigned-off-by: Jiang Xin <worldhello.net@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c                 |  7 ++++---\n t/t6040-tracking-info.sh | 34 +++++++++++++++++++++++++++++++++-\n wt-status.c              | 10 +++++-----\n 3 files changed, 42 insertions(+), 9 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 87c8dd3..7a8fe3f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1788,9 +1788,6 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\tupstream_is_gone = 1;\n \t\tbreak;\n \tdefault:\n-\t\t/* Nothing to report if neither side has changes. */\n-\t\tif (!ours && !theirs)\n-\t\t\treturn 0;\n \t\t/* with base */\n \t\tbreak;\n \t}\n@@ -1804,6 +1801,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\tif (advice_status_hints)\n \t\t\tstrbuf_addf(sb,\n \t\t\t\t_(\"  (use \\\"git branch --unset-upstream\\\" to fixup)\\n\"));\n+\t} else if (!ours && !theirs) {\n+\t\tstrbuf_addf(sb,\n+\t\t\t_(\"Your branch is identical to '%s'.\\n\"),\n+\t\t\tbase);\n \t} else if (!theirs) {\n \t\tstrbuf_addf(sb,\n \t\t\tQ_(\"Your branch is ahead of '%s' by %d commit.\\n\",\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 6f678a4..b24a18c 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -32,7 +32,8 @@ test_expect_success setup '\n \t\tgit checkout -b brokenbase origin &&\n \t\tgit checkout -b b5 --track brokenbase &&\n \t\tadvance g &&\n-\t\tgit branch -d brokenbase\n+\t\tgit branch -d brokenbase &&\n+\t\tgit checkout -b b6 origin\n \t) &&\n \tgit checkout -b follower --track master &&\n \tadvance h\n@@ -61,6 +62,7 @@ b2 origin/master: ahead 1, behind 1\n b3 origin/master: behind 1\n b4 origin/master: ahead 2\n b5 brokenbase: gone\n+b6 origin/master\n EOF\n \n test_expect_success 'branch -vv' '\n@@ -93,6 +95,13 @@ test_expect_success 'checkout (upstream is gone)' '\n \ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n '\n \n+test_expect_success 'checkout (identical to upstream)' '\n+\t(\n+\t\tcd test && git checkout b6\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n test_expect_success 'status (diverged from upstream)' '\n \t(\n \t\tcd test &&\n@@ -113,6 +122,16 @@ test_expect_success 'status (upstream is gone)' '\n \ttest_i18ngrep \"is based on .*, but the upstream is gone.\" actual\n '\n \n+test_expect_success 'status (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b6 >/dev/null &&\n+\t\t# reports nothing to commit\n+\t\ttest_must_fail git commit --dry-run\n+\t) >actual &&\n+\ttest_i18ngrep \"Your branch is identical to .origin/master\" actual\n+'\n+\n cat >expect <<\\EOF\n ## b1...origin/master [ahead 1, behind 1]\n EOF\n@@ -139,6 +158,19 @@ test_expect_success 'status -s -b (upstream is gone)' '\n \ttest_i18ncmp expect actual\n '\n \n+cat >expect <<\\EOF\n+## b6...origin/master\n+EOF\n+\n+test_expect_success 'status -s -b (identical to upstream)' '\n+\t(\n+\t\tcd test &&\n+\t\tgit checkout b6 >/dev/null &&\n+\t\tgit status -s -b | head -1\n+\t) >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 4b1713e..c5e6817 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1396,11 +1396,6 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \t\tupstream_is_gone = 1;\n \t\tbreak;\n \tdefault:\n-\t\t/* Stop reporting if neither side has changes. */\n-\t\tif (!num_ours && !num_theirs) {\n-\t\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n-\t\t\treturn;\n-\t\t}\n \t\t/* with base */\n \t\tbreak;\n \t}\n@@ -1410,6 +1405,11 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)\n \tcolor_fprintf(s->fp, header_color, \"...\");\n \tcolor_fprintf(s->fp, branch_color_remote, \"%s\", base);\n \n+\tif (!upstream_is_gone && !num_ours && !num_theirs) {\n+\t\tfputc(s->null_termination ? '\\0' : '\\n', s->fp);\n+\t\treturn;\n+\t}\n+\n \tcolor_fprintf(s->fp, header_color, \" [\");\n \tif (upstream_is_gone) {\n \t\tcolor_fprintf(s->fp, header_color, _(\"gone\"));\n-- \n1.8.4.rc3.2.g434fd97\n"},{"id":"225889","messageId":"xmqq7gf8kjdd.fsf@gitster.dls.corp.google.com","threadId":"34633","inReplyTo":"cover.1377500206.git.worldhello.net@gmail.com","subject":"Re: [PATCH v8 0/2] some enhancements for reporting branch tracking info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-26T07:21:18Z","receivedAt":"2013-08-26T07:21:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> Changes since v7:\n>\n> * Squashed patch 1/3 and patch 2/3 into one big patch.\n>\n> But not s/gone/absent/ as Matthieu suggested.\n\nThanks. Will requeue.\n"},{"id":"225890","messageId":"1861495981.5462037.1377503238201.JavaMail.root@openwide.fr","threadId":"34633","inReplyTo":"2f3a942d7049e80dca689aa68d494b70c288f2c7.1377500206.git.worldhello.net@gmail.com","subject":"Re: [PATCH v8 2/2] status: always show tracking branch even no change","fromName":"Jeremy Rosen","fromEmail":"jeremy.rosen@openwide.fr","sentAt":"2013-08-26T07:47:18Z","receivedAt":"2013-08-26T07:47:18Z","isPatch":true,"sender":{"key":"jeremy.rosen@openwide.fr","avatar":null},"body":"> \n> But this will not work if there is no change between the current\n> branch and its upstream. Always report upstream tracking info\n> even if there is no difference, so that \"git status\" is consistent\n> for checking tracking info for current branch. E.g.\n> \n>     $ git status\n>     # On branch feature1\n>     # Your branch is identical to 'github/feature1'.\n>     ...\n> \n>     $ git status -bs\n>     ## feature1...github/feature1\n>     ...\n> \n>     $ git checkout feature1\n>     Already on 'feature1'\n>     Your branch is identical to 'github/feature1'.\n>     ...\n> \n\n\nnitpicking, but shouldn't this be worded as \"up to date\" rather than \"identical\" ?\n\nThe reason is that identical gives the idea that the two branch happen to be on the same\ncommit wheras \"up to date\" gives the idea that there is a special relationship between\nthese two particular branches. We are not just listing all branches on the same\ncommit as us, we are actively telling you about this branch because it's interesting\nto you.\n"},{"id":"225891","messageId":"CANYiYbFNGZ=Y4BagNyrZEhO2c6O_J7g-MjA35fqBj2B9aXQf5w@mail.gmail.com","threadId":"34633","inReplyTo":"1861495981.5462037.1377503238201.JavaMail.root@openwide.fr","subject":"Re: [PATCH v8 2/2] status: always show tracking branch even no change","fromName":"Jiang Xin","fromEmail":"worldhello.net@gmail.com","sentAt":"2013-08-26T08:04:00Z","receivedAt":"2013-08-26T08:04:00Z","isPatch":true,"sender":{"key":"worldhello.net@gmail.com","avatar":"https://avatars.githubusercontent.com/u/183860?v=4"},"body":"2013/8/26 Jeremy Rosen <jeremy.rosen@openwide.fr>:\n>\n> nitpicking, but shouldn't this be worded as \"up to date\" rather than \"identical\" ?\n>\n> The reason is that identical gives the idea that the two branch happen to be on the same\n> commit wheras \"up to date\" gives the idea that there is a special relationship between\n> these two particular branches. We are not just listing all branches on the same\n> commit as us, we are actively telling you about this branch because it's interesting\n> to you.\n\nThat's better. I want to use 'up to date' in the beginning, but I don't know\nwhich prep. should be used. Now I realize I should:\n\n    s/identical to/up to date with/\n\n-- \nJiang Xin\n"},{"id":"225904","messageId":"xmqqvc2sigdp.fsf@gitster.dls.corp.google.com","threadId":"34633","inReplyTo":"CANYiYbFNGZ=Y4BagNyrZEhO2c6O_J7g-MjA35fqBj2B9aXQf5w@mail.gmail.com","subject":"Re: [PATCH v8 2/2] status: always show tracking branch even no change","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-08-26T16:08:50Z","receivedAt":"2013-08-26T16:08:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jiang Xin <worldhello.net@gmail.com> writes:\n\n> 2013/8/26 Jeremy Rosen <jeremy.rosen@openwide.fr>:\n>>\n>> nitpicking, but shouldn't this be worded as \"up to date\" rather than \"identical\" ?\n>>\n>> The reason is that identical gives the idea that the two branch happen to be on the same\n>> commit wheras \"up to date\" gives the idea that there is a special relationship between\n>> these two particular branches. We are not just listing all branches on the same\n>> commit as us, we are actively telling you about this branch because it's interesting\n>> to you.\n>\n> That's better. I want to use 'up to date' in the beginning, but I don't know\n> which prep. should be used. Now I realize I should:\n>\n>     s/identical to/up to date with/\n\nYeah, that, or \"in sync with\" which may be a bit shorter.\n\nI'll queue with \"up-to-date with\", as \"git grep 'up to date'\" tells\nme that it is less common than \"git grep 'up-to-date'\", for now.\n\nThanks.\n"}]}