Merge branch 'jk/partial-clone-sparse-blob'
authorJunio C Hamano <gitster@pobox.com>
Mon, 7 Oct 2019 02:32:54 +0000 (11:32 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 7 Oct 2019 02:32:54 +0000 (11:32 +0900)
The name of the blob object that stores the filter specification
for sparse cloning/fetching was interpreted in a wrong place in the
code, causing Git to abort.

* jk/partial-clone-sparse-blob:
  list-objects-filter: use empty string instead of NULL for sparse "base"
  list-objects-filter: give a more specific error sparse parsing error
  list-objects-filter: delay parsing of sparse oid
  t5616: test cloning/fetching with sparse:oid=<oid> filter

builtin/rev-list.c
list-objects-filter-options.c
list-objects-filter-options.h
list-objects-filter.c
t/t5616-partial-clone.sh

index b8dc2e1..74dbfad 100644 (file)
@@ -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))) {
index 4d88bfe..256bcfb 100644 (file)
@@ -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 <oid-expression> 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);
index b63c5ee..2ffb392 100644 (file)
@@ -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;
 
index d624f1c..1e8d4e7 100644 (file)
@@ -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 */
index fc634a5..79f7b65 100755 (executable)
@@ -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