diff --git a/builtin/rev-list.c b/builtin/rev-list.c index b8dc2e1fba..74dbfad73d 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -471,12 +471,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) parse_list_objects_filter(&filter_options, arg); if (filter_options.choice && !revs.blob_objects) die(_("object filtering requires --objects")); - if (filter_options.choice == LOFC_SPARSE_OID && - !filter_options.sparse_oid_value) - die( - _("invalid sparse value '%s'"), - list_objects_filter_spec( - &filter_options)); continue; } if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) { diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c index 4d88bfe64a..256bcfbdfe 100644 --- a/list-objects-filter-options.c +++ b/list-objects-filter-options.c @@ -62,17 +62,7 @@ static int gently_parse_list_objects_filter( return 0; } else if (skip_prefix(arg, "sparse:oid=", &v0)) { - struct object_context oc; - struct object_id sparse_oid; - - /* - * Try to parse into an OID for the current - * command, but DO NOT complain if we don't have the blob or - * ref locally. - */ - if (!get_oid_with_context(the_repository, v0, GET_OID_BLOB, - &sparse_oid, &oc)) - filter_options->sparse_oid_value = oiddup(&sparse_oid); + filter_options->sparse_oid_name = xstrdup(v0); filter_options->choice = LOFC_SPARSE_OID; return 0; @@ -320,7 +310,7 @@ void list_objects_filter_release( if (!filter_options) return; string_list_clear(&filter_options->filter_spec, /*free_util=*/0); - free(filter_options->sparse_oid_value); + free(filter_options->sparse_oid_name); for (sub = 0; sub < filter_options->sub_nr; sub++) list_objects_filter_release(&filter_options->sub[sub]); free(filter_options->sub); diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h index b63c5ee1a3..2ffb39222c 100644 --- a/list-objects-filter-options.h +++ b/list-objects-filter-options.h @@ -45,7 +45,7 @@ struct list_objects_filter_options { * some values will be defined for any given choice. */ - struct object_id *sparse_oid_value; + char *sparse_oid_name; unsigned long blob_limit_value; unsigned long tree_exclude_depth; diff --git a/list-objects-filter.c b/list-objects-filter.c index d624f1c898..1e8d4e763d 100644 --- a/list-objects-filter.c +++ b/list-objects-filter.c @@ -483,9 +483,17 @@ static void filter_sparse_oid__init( struct filter *filter) { struct filter_sparse_data *d = xcalloc(1, sizeof(*d)); - if (add_patterns_from_blob_to_list(filter_options->sparse_oid_value, - NULL, 0, &d->pl) < 0) - die("could not load filter specification"); + struct object_context oc; + struct object_id sparse_oid; + + if (get_oid_with_context(the_repository, + filter_options->sparse_oid_name, + GET_OID_BLOB, &sparse_oid, &oc)) + die(_("unable to access sparse blob in '%s'"), + filter_options->sparse_oid_name); + if (add_patterns_from_blob_to_list(&sparse_oid, "", 0, &d->pl) < 0) + die(_("unable to parse sparse filter data in %s"), + oid_to_hex(&sparse_oid)); ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc); d->array_frame[d->nr].default_match = 0; /* default to include */ diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh index fc634a56b2..79f7b65f8c 100755 --- a/t/t5616-partial-clone.sh +++ b/t/t5616-partial-clone.sh @@ -260,6 +260,42 @@ test_expect_success 'fetch what is specified on CLI even if already promised' ' ! grep "?$(cat blob)" missing_after ' +test_expect_success 'setup src repo for sparse filter' ' + git init sparse-src && + git -C sparse-src config --local uploadpack.allowfilter 1 && + git -C sparse-src config --local uploadpack.allowanysha1inwant 1 && + test_commit -C sparse-src one && + test_commit -C sparse-src two && + echo /one.t >sparse-src/only-one && + git -C sparse-src add . && + git -C sparse-src commit -m "add sparse checkout files" +' + +test_expect_success 'partial clone with sparse filter succeeds' ' + rm -rf dst.git && + git clone --no-local --bare \ + --filter=sparse:oid=master:only-one \ + sparse-src dst.git && + ( + cd dst.git && + git rev-list --objects --missing=print HEAD >out && + grep "^$(git rev-parse HEAD:one.t)" out && + grep "^?$(git rev-parse HEAD:two.t)" out + ) +' + +test_expect_success 'partial clone with unresolvable sparse filter fails cleanly' ' + rm -rf dst.git && + test_must_fail git clone --no-local --bare \ + --filter=sparse:oid=master:no-such-name \ + sparse-src dst.git 2>err && + test_i18ngrep "unable to access sparse blob in .master:no-such-name" err && + test_must_fail git clone --no-local --bare \ + --filter=sparse:oid=master \ + sparse-src dst.git 2>err && + test_i18ngrep "unable to parse sparse filter data in" err +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd