for-each-ref: always check stat_tracking_info()'s return value

The code handling %(upstream:track) and %(upstream:trackshort) assumed that it always had a valid branch that had been sanitized earlier in populate_value(), and thus did not check the return value of the call to stat_tracking_info(). While there is indeed some sanitization code that basically corresponds to stat_tracking_info() returning 0 (no base branch set), the function can also return -1 when the base branch did exist but has since then been deleted. In this case, num_ours and num_theirs had undefined values and a call to `git for-each-ref --format="%(upstream:track)"` could print spurious values such as [behind -111794512] [ahead 38881640, behind 5103867] even for repositories with one single commit. Verify stat_tracking_info()'s return value and do not print anything if it returns -1. This behavior also matches the documentation ("has no effect if the ref does not have tracking information associated with it"). Helped-by: Eric Sunshine <sunshine@sunshineco.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Raphael Kubo da Costa committed Jan 5, 2015 at 11:58 UTC b6160d950c9ef168d0f7d7c9b2812f280e5b88fb
2 files changed +22 -2
builtin/for-each-ref.c
+9 -2
@@ -728,7 +728,10 @@ static void populate_value(struct refinfo *ref)
728 starts_with(name, "upstream")) {
729 char buf[40];
730
731 - stat_tracking_info(branch, &num_ours, &num_theirs);
731 + if (stat_tracking_info(branch, &num_ours,
732 + &num_theirs) != 1)
733 + continue;
734 +
735 if (!num_ours && !num_theirs)
736 v->s = "";
737 else if (!num_ours) {
@@ -746,7 +749,11 @@ static void populate_value(struct refinfo *ref)
749 } else if (!strcmp(formatp, "trackshort") &&
750 starts_with(name, "upstream")) {
751 assert(branch);
749 - stat_tracking_info(branch, &num_ours, &num_theirs);
752 +
753 + if (stat_tracking_info(branch, &num_ours,
754 + &num_theirs) != 1)
755 + continue;
756 +
757 if (!num_ours && !num_theirs)
758 v->s = "=";
759 else if (!num_ours)
t/t6300-for-each-ref.sh
+13
@@ -334,6 +334,19 @@ test_expect_success 'Check that :track[short] cannot be used with other atoms' '
334 test_must_fail git for-each-ref --format="%(refname:trackshort)" 2>/dev/null
335 '
336
337 +test_expect_success 'Check that :track[short] works when upstream is invalid' '
338 + cat >expected <<-\EOF &&
339 +
340 +
341 + EOF
342 + test_when_finished "git config branch.master.merge refs/heads/master" &&
343 + git config branch.master.merge refs/heads/does-not-exist &&
344 + git for-each-ref \
345 + --format="%(upstream:track)$LF%(upstream:trackshort)" \
346 + refs/heads >actual &&
347 + test_cmp expected actual
348 +'
349 +
350 cat >expected <<EOF
351 $(git rev-parse --short HEAD)
352 EOF