fetch-pack: add specific error for fetching an unadvertised object

Enhance filter_refs (which decides whether a request for an unadvertised object should be sent to the server) to record a new match status on the "struct ref" when a request is not allowed, and have report_unmatched_refs check for this status and print a special error message, "Server does not allow request for unadvertised object". Signed-off-by: Matt McCutchen <matt@mattmccutchen.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matt McCutchen committed Feb 22, 2017 at 11:05 UTC d56583ded679f2eade3994d855c8d605e2964710
3 files changed +35 -18
fetch-pack.c
+27 -15
@@ -578,7 +578,7 @@ static void filter_refs(struct fetch_pack_args *args,
578 break; /* definitely do not have it */
579 else if (cmp == 0) {
580 keep = 1; /* definitely have it */
581 - sought[i]->matched = 1;
581 + sought[i]->match_status = REF_MATCHED;
582 }
583 i++;
584 }
@@ -598,22 +598,24 @@ static void filter_refs(struct fetch_pack_args *args,
598 }
599
600 /* Append unmatched requests to the list */
601 - if ((allow_unadvertised_object_request &
602 - (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
603 - for (i = 0; i < nr_sought; i++) {
604 - unsigned char sha1[20];
601 + for (i = 0; i < nr_sought; i++) {
602 + unsigned char sha1[20];
603
606 - ref = sought[i];
607 - if (ref->matched)
608 - continue;
609 - if (get_sha1_hex(ref->name, sha1) ||
610 - ref->name[40] != '\0' ||
611 - hashcmp(sha1, ref->old_oid.hash))
612 - continue;
604 + ref = sought[i];
605 + if (ref->match_status != REF_NOT_MATCHED)
606 + continue;
607 + if (get_sha1_hex(ref->name, sha1) ||
608 + ref->name[40] != '\0' ||
609 + hashcmp(sha1, ref->old_oid.hash))
610 + continue;
611
614 - ref->matched = 1;
612 + if ((allow_unadvertised_object_request &
613 + (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
614 + ref->match_status = REF_MATCHED;
615 *newtail = copy_ref(ref);
616 newtail = &(*newtail)->next;
617 + } else {
618 + ref->match_status = REF_UNADVERTISED_NOT_ALLOWED;
619 }
620 }
621 *refs = newlist;
@@ -1100,9 +1102,19 @@ int report_unmatched_refs(struct ref **sought, int nr_sought)
1102 int i, ret = 0;
1103
1104 for (i = 0; i < nr_sought; i++) {
1103 - if (!sought[i] || sought[i]->matched)
1105 + if (!sought[i])
1106 continue;
1105 - error(_("no such remote ref %s"), sought[i]->name);
1107 + switch (sought[i]->match_status) {
1108 + case REF_MATCHED:
1109 + continue;
1110 + case REF_NOT_MATCHED:
1111 + error(_("no such remote ref %s"), sought[i]->name);
1112 + break;
1113 + case REF_UNADVERTISED_NOT_ALLOWED:
1114 + error(_("Server does not allow request for unadvertised object %s"),
1115 + sought[i]->name);
1116 + break;
1117 + }
1118 ret = 1;
1119 }
1120 return ret;
remote.h
+7 -2
@@ -89,8 +89,13 @@ struct ref {
89 force:1,
90 forced_update:1,
91 expect_old_sha1:1,
92 - deletion:1,
93 - matched:1;
92 + deletion:1;
93 +
94 + enum {
95 + REF_NOT_MATCHED = 0, /* initial value */
96 + REF_MATCHED,
97 + REF_UNADVERTISED_NOT_ALLOWED
98 + } match_status;
99
100 /*
101 * Order is important here, as we write to FETCH_HEAD
t/t5516-fetch-push.sh
+1 -1
@@ -1099,7 +1099,7 @@ test_expect_success 'fetch exact SHA1' '
1099
1100 # fetching the hidden object should fail by default
1101 test_must_fail git fetch -v ../testrepo $the_commit:refs/heads/copy 2>err &&
1102 - test_i18ngrep "no such remote ref" err &&
1102 + test_i18ngrep "Server does not allow request for unadvertised object" err &&
1103 test_must_fail git rev-parse --verify refs/heads/copy &&
1104
1105 # the server side can allow it to succeed