]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/clone.c
Sync with 2.35.7
[thirdparty/git.git] / builtin / clone.c
index 4541a55013d75ca8d662797fbe2dad9ce7a8d52e..7d3a3ffb40804d2bc9211263587b6109bcb24426 100644 (file)
@@ -32,6 +32,8 @@
 #include "connected.h"
 #include "packfile.h"
 #include "list-objects-filter-options.h"
+#include "hook.h"
+#include "bundle.h"
 
 /*
  * Overall FIXMEs:
@@ -71,6 +73,8 @@ static int option_dissociate;
 static int max_jobs = -1;
 static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
 static struct list_objects_filter_options filter_options;
+static int option_filter_submodules = -1;    /* unspecified */
+static int config_filter_submodules = -1;    /* unspecified */
 static struct string_list server_options = STRING_LIST_INIT_NODUP;
 static int option_remote_submodules;
 
@@ -150,6 +154,8 @@ static struct option builtin_clone_options[] = {
        OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
                        TRANSPORT_FAMILY_IPV6),
        OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+       OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
+                   N_("apply partial clone filters to submodules")),
        OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
                    N_("any cloned submodules will use their remote-tracking branch")),
        OPT_BOOL(0, "sparse", &option_sparse_checkout,
@@ -652,7 +658,7 @@ static int git_sparse_checkout_init(const char *repo)
        return result;
 }
 
-static int checkout(int submodule_progress)
+static int checkout(int submodule_progress, int filter_submodules)
 {
        struct object_id oid;
        char *head;
@@ -697,6 +703,8 @@ static int checkout(int submodule_progress)
        init_checkout_metadata(&opts.meta, head, &oid, NULL);
 
        tree = parse_tree_indirect(&oid);
+       if (!tree)
+               die(_("unable to parse commit %s"), oid_to_hex(&oid));
        parse_tree(tree);
        init_tree_desc(&t, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts) < 0)
@@ -707,7 +715,7 @@ static int checkout(int submodule_progress)
        if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
 
-       err |= run_hook_le(NULL, "post-checkout", oid_to_hex(null_oid()),
+       err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
                           oid_to_hex(&oid), "1", NULL);
 
        if (!err && (option_recurse_submodules.nr > 0)) {
@@ -731,6 +739,10 @@ static int checkout(int submodule_progress)
                        strvec_push(&args, "--no-fetch");
                }
 
+               if (filter_submodules && filter_options.choice)
+                       strvec_pushf(&args, "--filter=%s",
+                                    expand_list_objects_filter_spec(&filter_options));
+
                if (option_single_branch >= 0)
                        strvec_push(&args, option_single_branch ?
                                               "--single-branch" :
@@ -751,6 +763,8 @@ static int git_clone_config(const char *k, const char *v, void *cb)
        }
        if (!strcmp(k, "clone.rejectshallow"))
                config_reject_shallow = git_config_bool(k, v);
+       if (!strcmp(k, "clone.filtersubmodules"))
+               config_filter_submodules = git_config_bool(k, v);
 
        return git_default_config(k, v, cb);
 }
@@ -864,7 +878,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        const struct ref *refs, *remote_head;
        struct ref *remote_head_points_at = NULL;
        const struct ref *our_head_points_at;
-       struct ref *mapped_refs;
+       struct ref *mapped_refs = NULL;
        const struct ref *ref;
        struct strbuf key = STRBUF_INIT;
        struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
@@ -873,6 +887,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        struct remote *remote;
        int err = 0, complete_refs_before_fetch = 1;
        int submodule_progress;
+       int filter_submodules = 0;
 
        struct transport_ls_refs_options transport_ls_refs_options =
                TRANSPORT_LS_REFS_OPTIONS_INIT;
@@ -1068,12 +1083,35 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (option_reject_shallow != -1)
                reject_shallow = option_reject_shallow;
 
+       /*
+        * If option_filter_submodules is specified from CLI option,
+        * ignore config_filter_submodules from git_clone_config.
+        */
+       if (config_filter_submodules != -1)
+               filter_submodules = config_filter_submodules;
+       if (option_filter_submodules != -1)
+               filter_submodules = option_filter_submodules;
+
+       /*
+        * Exit if the user seems to be doing something silly with submodule
+        * filter flags (but not with filter configs, as those should be
+        * set-and-forget).
+        */
+       if (option_filter_submodules > 0 && !filter_options.choice)
+               die(_("the option '%s' requires '%s'"),
+                   "--also-filter-submodules", "--filter");
+       if (option_filter_submodules > 0 && !option_recurse_submodules.nr)
+               die(_("the option '%s' requires '%s'"),
+                   "--also-filter-submodules", "--recurse-submodules");
+
        /*
         * apply the remote name provided by --origin only after this second
         * call to git_config, to ensure it overrides all config-based values.
         */
-       if (option_origin != NULL)
+       if (option_origin != NULL) {
+               free(remote_name);
                remote_name = xstrdup(option_origin);
+       }
 
        if (remote_name == NULL)
                remote_name = xstrdup("origin");
@@ -1139,6 +1177,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        transport->family = family;
        transport->cloning = 1;
 
+       if (is_bundle) {
+               struct bundle_header header = BUNDLE_HEADER_INIT;
+               int fd = read_bundle_header(path, &header);
+               int has_filter = header.filter.choice != LOFC_DISABLED;
+
+               if (fd > 0)
+                       close(fd);
+               bundle_header_release(&header);
+               if (has_filter)
+                       die(_("cannot clone from filtered bundle"));
+       }
+
        transport_set_option(transport, TRANS_OPT_KEEP, "yes");
 
        if (reject_shallow)
@@ -1186,7 +1236,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
 
-       if (refs) {
+       if (refs)
+               mapped_refs = wanted_peer_refs(refs, &remote->fetch);
+
+       if (mapped_refs) {
                int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
 
                /*
@@ -1195,8 +1248,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                 */
                initialize_repository_version(hash_algo, 1);
                repo_set_hash_algo(the_repository, hash_algo);
-
-               mapped_refs = wanted_peer_refs(refs, &remote->fetch);
                /*
                 * transport_get_remote_refs() may return refs with null sha-1
                 * in mapped_refs (see struct transport->get_refs_list
@@ -1235,14 +1286,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        }
        else {
                const char *branch;
-               char *ref;
+               const char *ref;
+               char *ref_free = NULL;
 
                if (option_branch)
                        die(_("Remote branch %s not found in upstream %s"),
                                        option_branch, remote_name);
 
                warning(_("You appear to have cloned an empty repository."));
-               mapped_refs = NULL;
                our_head_points_at = NULL;
                remote_head_points_at = NULL;
                remote_head = NULL;
@@ -1252,17 +1303,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                    skip_prefix(transport_ls_refs_options.unborn_head_target,
                                "refs/heads/", &branch)) {
                        ref = transport_ls_refs_options.unborn_head_target;
-                       transport_ls_refs_options.unborn_head_target = NULL;
                        create_symref("HEAD", ref, reflog_msg.buf);
                } else {
                        branch = git_default_branch_name(0);
-                       ref = xstrfmt("refs/heads/%s", branch);
+                       ref_free = xstrfmt("refs/heads/%s", branch);
+                       ref = ref_free;
                }
 
                if (!option_bare)
                        install_branch_config(0, branch, remote_name, ref);
-
-               free(ref);
+               free(ref_free);
        }
 
        write_refspec_config(src_ref_prefix, our_head_points_at,
@@ -1273,7 +1323,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        if (is_local)
                clone_local(path, git_dir);
-       else if (refs && complete_refs_before_fetch) {
+       else if (mapped_refs && complete_refs_before_fetch) {
                if (transport_fetch_refs(transport, mapped_refs))
                        die(_("remote transport reported error"));
        }
@@ -1301,7 +1351,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        }
 
        junk_mode = JUNK_LEAVE_REPO;
-       err = checkout(submodule_progress);
+       err = checkout(submodule_progress, filter_submodules);
 
        free(remote_name);
        strbuf_release(&reflog_msg);
@@ -1314,7 +1364,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        UNLEAK(repo);
        junk_mode = JUNK_LEAVE_ALL;
 
-       strvec_clear(&transport_ls_refs_options.ref_prefixes);
-       free(transport_ls_refs_options.unborn_head_target);
+       transport_ls_refs_options_release(&transport_ls_refs_options);
        return err;
 }