Merge branch 'nd/worktree-kill-parse-ref'
[gitweb.git] / builtin / submodule--helper.c
index 84562ec8337a49c823da6c641d73cd363a972f27..818fe74f0af8696fe21a75d4aaf6b919b645d22b 100644 (file)
@@ -275,8 +275,6 @@ static void module_list_active(struct module_list *list)
        int i;
        struct module_list active_modules = MODULE_LIST_INIT;
 
-       gitmodules_config();
-
        for (i = 0; i < list->nr; i++) {
                const struct cache_entry *ce = list->entries[i];
 
@@ -337,9 +335,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
        struct strbuf sb = STRBUF_INIT;
        char *upd = NULL, *url = NULL, *displaypath;
 
-       /* Only loads from .gitmodules, no overlay with .git/config */
-       gitmodules_config();
-
        if (prefix && get_super_prefix())
                die("BUG: cannot have prefix and superprefix");
        else if (prefix)
@@ -475,7 +470,6 @@ static int module_name(int argc, const char **argv, const char *prefix)
        if (argc != 2)
                usage(_("git submodule--helper name <path>"));
 
-       gitmodules_config();
        sub = submodule_from_path(&null_oid, argv[1]);
 
        if (!sub)
@@ -780,6 +774,10 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                                           struct strbuf *out)
 {
        const struct submodule *sub = NULL;
+       const char *url = NULL;
+       const char *update_string;
+       enum submodule_update_type update_type;
+       char *key;
        struct strbuf displaypath_sb = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
        const char *displaypath = NULL;
@@ -808,9 +806,17 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                goto cleanup;
        }
 
+       key = xstrfmt("submodule.%s.update", sub->name);
+       if (!repo_config_get_string_const(the_repository, key, &update_string)) {
+               update_type = parse_submodule_update_type(update_string);
+       } else {
+               update_type = sub->update_strategy.type;
+       }
+       free(key);
+
        if (suc->update.type == SM_UPDATE_NONE
            || (suc->update.type == SM_UPDATE_UNSPECIFIED
-               && sub->update_strategy.type == SM_UPDATE_NONE)) {
+               && update_type == SM_UPDATE_NONE)) {
                strbuf_addf(out, _("Skipping submodule '%s'"), displaypath);
                strbuf_addch(out, '\n');
                goto cleanup;
@@ -822,6 +828,11 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                goto cleanup;
        }
 
+       strbuf_reset(&sb);
+       strbuf_addf(&sb, "submodule.%s.url", sub->name);
+       if (repo_config_get_string_const(the_repository, sb.buf, &url))
+               url = sub->url;
+
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s/.git", ce->name);
        needs_cloning = !file_exists(sb.buf);
@@ -851,7 +862,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                argv_array_push(&child->args, "--depth=1");
        argv_array_pushl(&child->args, "--path", sub->path, NULL);
        argv_array_pushl(&child->args, "--name", sub->name, NULL);
-       argv_array_pushl(&child->args, "--url", sub->url, NULL);
+       argv_array_pushl(&child->args, "--url", url, NULL);
        if (suc->references.nr) {
                struct string_list_item *item;
                for_each_string_list_item(item, &suc->references)
@@ -960,10 +971,19 @@ static int update_clone_task_finished(int result,
        return 0;
 }
 
+static int gitmodules_update_clone_config(const char *var, const char *value,
+                                         void *cb)
+{
+       int *max_jobs = cb;
+       if (!strcmp(var, "submodule.fetchjobs"))
+               *max_jobs = parse_submodule_fetchjobs(var, value);
+       return 0;
+}
+
 static int update_clone(int argc, const char **argv, const char *prefix)
 {
        const char *update = NULL;
-       int max_jobs = -1;
+       int max_jobs = 1;
        struct string_list_item *item;
        struct pathspec pathspec;
        struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
@@ -1000,6 +1020,9 @@ static int update_clone(int argc, const char **argv, const char *prefix)
        };
        suc.prefix = prefix;
 
+       config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
+       git_config(gitmodules_update_clone_config, &max_jobs);
+
        argc = parse_options(argc, argv, prefix, module_update_clone_options,
                             git_submodule_helper_usage, 0);
 
@@ -1013,13 +1036,6 @@ static int update_clone(int argc, const char **argv, const char *prefix)
        if (pathspec.nr)
                suc.warn_if_uninitialized = 1;
 
-       /* Overlay the parsed .gitmodules file with .git/config */
-       gitmodules_config();
-       git_config(submodule_config, NULL);
-
-       if (max_jobs < 0)
-               max_jobs = parallel_submodules();
-
        run_processes_parallel(max_jobs,
                               update_clone_get_next_task,
                               update_clone_start_failure,
@@ -1057,17 +1073,22 @@ static int resolve_relative_path(int argc, const char **argv, const char *prefix
 static const char *remote_submodule_branch(const char *path)
 {
        const struct submodule *sub;
-       gitmodules_config();
-       git_config(submodule_config, NULL);
+       const char *branch = NULL;
+       char *key;
 
        sub = submodule_from_path(&null_oid, path);
        if (!sub)
                return NULL;
 
-       if (!sub->branch)
+       key = xstrfmt("submodule.%s.branch", sub->name);
+       if (repo_config_get_string_const(the_repository, key, &branch))
+               branch = sub->branch;
+       free(key);
+
+       if (!branch)
                return "master";
 
-       if (!strcmp(sub->branch, ".")) {
+       if (!strcmp(branch, ".")) {
                unsigned char sha1[20];
                const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
 
@@ -1085,7 +1106,7 @@ static const char *remote_submodule_branch(const char *path)
                return refname;
        }
 
-       return sub->branch;
+       return branch;
 }
 
 static int resolve_remote_submodule_branch(int argc, const char **argv,
@@ -1108,9 +1129,28 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,
 static int push_check(int argc, const char **argv, const char *prefix)
 {
        struct remote *remote;
+       const char *superproject_head;
+       char *head;
+       int detached_head = 0;
+       struct object_id head_oid;
+
+       if (argc < 3)
+               die("submodule--helper push-check requires at least 2 arguments");
 
-       if (argc < 2)
-               die("submodule--helper push-check requires at least 1 argument");
+       /*
+        * superproject's resolved head ref.
+        * if HEAD then the superproject is in a detached head state, otherwise
+        * it will be the resolved head ref.
+        */
+       superproject_head = argv[1];
+       argv++;
+       argc--;
+       /* Get the submodule's head ref and determine if it is detached */
+       head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       if (!head)
+               die(_("Failed to resolve HEAD as a valid ref."));
+       if (!strcmp(head, "HEAD"))
+               detached_head = 1;
 
        /*
         * The remote must be configured.
@@ -1133,18 +1173,30 @@ static int push_check(int argc, const char **argv, const char *prefix)
                        if (rs->pattern || rs->matching)
                                continue;
 
-                       /*
-                        * LHS must match a single ref
-                        * NEEDSWORK: add logic to special case 'HEAD' once
-                        * working with submodules in a detached head state
-                        * ceases to be the norm.
-                        */
-                       if (count_refspec_match(rs->src, local_refs, NULL) != 1)
+                       /* LHS must match a single ref */
+                       switch (count_refspec_match(rs->src, local_refs, NULL)) {
+                       case 1:
+                               break;
+                       case 0:
+                               /*
+                                * If LHS matches 'HEAD' then we need to ensure
+                                * that it matches the same named branch
+                                * checked out in the superproject.
+                                */
+                               if (!strcmp(rs->src, "HEAD")) {
+                                       if (!detached_head &&
+                                           !strcmp(head, superproject_head))
+                                               break;
+                                       die("HEAD does not match the named branch in the superproject");
+                               }
+                       default:
                                die("src refspec '%s' must name a ref",
                                    rs->src);
+                       }
                }
                free_refspec(refspec_nr, refspec);
        }
+       free(head);
 
        return 0;
 }
@@ -1173,9 +1225,6 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, embed_gitdir_options,
                             git_submodule_helper_usage, 0);
 
-       gitmodules_config();
-       git_config(submodule_config, NULL);
-
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
                return 1;
 
@@ -1191,8 +1240,6 @@ static int is_active(int argc, const char **argv, const char *prefix)
        if (argc != 2)
                die("submodule--helper is-active takes exactly 1 argument");
 
-       gitmodules_config();
-
        return !is_submodule_active(the_repository, argv[1]);
 }