Merge branch 'ah/doc-interpret-trailers-ifexists' into maint
[gitweb.git] / builtin / submodule--helper.c
index be316bbbc898c9311c6ec82aa0cfbc808f04e8c9..566a5b6a6f8937742e83577918a94f0dcb20c66c 100644 (file)
@@ -270,6 +270,29 @@ static int module_list_compute(int argc, const char **argv,
        return result;
 }
 
+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];
+
+               if (!is_submodule_initialized(ce->name))
+                       continue;
+
+               ALLOC_GROW(active_modules.entries,
+                          active_modules.nr + 1,
+                          active_modules.alloc);
+               active_modules.entries[active_modules.nr++] = ce;
+       }
+
+       free(list->entries);
+       *list = active_modules;
+}
+
 static int module_list(int argc, const char **argv, const char *prefix)
 {
        int i;
@@ -333,6 +356,18 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
                die(_("No url found for submodule path '%s' in .gitmodules"),
                        displaypath);
 
+       /*
+        * NEEDSWORK: In a multi-working-tree world, this needs to be
+        * set in the per-worktree config.
+        *
+        * Set active flag for the submodule being initialized
+        */
+       if (!is_submodule_initialized(path)) {
+               strbuf_reset(&sb);
+               strbuf_addf(&sb, "submodule.%s.active", sub->name);
+               git_config_set_gently(sb.buf, "true");
+       }
+
        /*
         * Copy url setting when it is not set yet.
         * To look up the url in .git/config, we must not fall back to
@@ -341,12 +376,12 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
        strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.url", sub->name);
        if (git_config_get_string(sb.buf, &url)) {
-               url = xstrdup(sub->url);
-
-               if (!url)
+               if (!sub->url)
                        die(_("No url found for submodule path '%s' in .gitmodules"),
                                displaypath);
 
+               url = xstrdup(sub->url);
+
                /* Possibly a url relative to parent */
                if (starts_with_dot_dot_slash(url) ||
                    starts_with_dot_slash(url)) {
@@ -420,6 +455,13 @@ static int module_init(int argc, const char **argv, const char *prefix)
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
                return 1;
 
+       /*
+        * If there are no path args and submodule.active is set then,
+        * by default, only initialize 'active' modules.
+        */
+       if (!argc && git_config_get_value_multi("submodule.active"))
+               module_list_active(&list);
+
        for (i = 0; i < list.nr; i++)
                init_submodule(list.entries[i]->name, prefix, quiet);
 
@@ -741,7 +783,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
        struct strbuf displaypath_sb = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
        const char *displaypath = NULL;
-       char *url = NULL;
        int needs_cloning = 0;
 
        if (ce_stage(ce)) {
@@ -775,15 +816,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                goto cleanup;
        }
 
-       /*
-        * Looking up the url in .git/config.
-        * We must not fall back to .gitmodules as we only want
-        * to process configured submodules.
-        */
-       strbuf_reset(&sb);
-       strbuf_addf(&sb, "submodule.%s.url", sub->name);
-       git_config_get_string(sb.buf, &url);
-       if (!url) {
+       /* Check if the submodule has been initialized. */
+       if (!is_submodule_initialized(ce->name)) {
                next_submodule_warn_missing(suc, out, displaypath);
                goto cleanup;
        }
@@ -817,7 +851,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", url, NULL);
+       argv_array_pushl(&child->args, "--url", sub->url, NULL);
        if (suc->references.nr) {
                struct string_list_item *item;
                for_each_string_list_item(item, &suc->references)
@@ -827,7 +861,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                argv_array_push(&child->args, suc->depth);
 
 cleanup:
-       free(url);
        strbuf_reset(&displaypath_sb);
        strbuf_reset(&sb);
 
@@ -1072,6 +1105,50 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,
        return 0;
 }
 
+static int push_check(int argc, const char **argv, const char *prefix)
+{
+       struct remote *remote;
+
+       if (argc < 2)
+               die("submodule--helper push-check requires at least 1 argument");
+
+       /*
+        * The remote must be configured.
+        * This is to avoid pushing to the exact same URL as the parent.
+        */
+       remote = pushremote_get(argv[1]);
+       if (!remote || remote->origin == REMOTE_UNCONFIGURED)
+               die("remote '%s' not configured", argv[1]);
+
+       /* Check the refspec */
+       if (argc > 2) {
+               int i, refspec_nr = argc - 2;
+               struct ref *local_refs = get_local_heads();
+               struct refspec *refspec = parse_push_refspec(refspec_nr,
+                                                            argv + 2);
+
+               for (i = 0; i < refspec_nr; i++) {
+                       struct refspec *rs = refspec + i;
+
+                       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)
+                               die("src refspec '%s' must name a ref",
+                                   rs->src);
+               }
+               free_refspec(refspec_nr, refspec);
+       }
+
+       return 0;
+}
+
 static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 {
        int i;
@@ -1109,6 +1186,16 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
+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_initialized(argv[1]);
+}
+
 #define SUPPORT_SUPER_PREFIX (1<<0)
 
 struct cmd_struct {
@@ -1127,7 +1214,9 @@ static struct cmd_struct commands[] = {
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
        {"init", module_init, SUPPORT_SUPER_PREFIX},
        {"remote-branch", resolve_remote_submodule_branch, 0},
+       {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
+       {"is-active", is_active, 0},
 };
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)