fetch/pull: Describe --recurse-submodule restrictions in the BUGS section
[gitweb.git] / submodule.c
index afb0a0e3fe588a756578642b7f063b14000fe910..88c7488a63bf2a3280cdc536609a1d2b15541d0c 100644 (file)
@@ -113,7 +113,7 @@ int parse_submodule_config_option(const char *var, const char *value)
                if (!config)
                        config = string_list_append(&config_fetch_recurse_submodules_for_name,
                                                    strbuf_detach(&submodname, NULL));
-               config->util = git_config_bool(var, value) ? (void *)1 : NULL;
+               config->util = (void *)(intptr_t)parse_fetch_recurse_submodules_arg(var, value);
                strbuf_release(&submodname);
        } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) {
                if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
@@ -263,6 +263,33 @@ void set_config_fetch_recurse_submodules(int value)
        config_fetch_recurse_submodules = value;
 }
 
+static int is_submodule_commit_present(const char *path, unsigned char sha1[20])
+{
+       int is_present = 0;
+       if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) {
+               /* Even if the submodule is checked out and the commit is
+                * present, make sure it is reachable from a ref. */
+               struct child_process cp;
+               const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL};
+               struct strbuf buf = STRBUF_INIT;
+
+               argv[3] = sha1_to_hex(sha1);
+               memset(&cp, 0, sizeof(cp));
+               cp.argv = argv;
+               cp.env = local_repo_env;
+               cp.git_cmd = 1;
+               cp.no_stdin = 1;
+               cp.out = -1;
+               cp.dir = path;
+               if (!run_command(&cp) && !strbuf_read(&buf, cp.out, 1024))
+                       is_present = 1;
+
+               close(cp.out);
+               strbuf_release(&buf);
+       }
+       return is_present;
+}
+
 static void submodule_collect_changed_cb(struct diff_queue_struct *q,
                                         struct diff_options *options,
                                         void *data)
@@ -280,7 +307,7 @@ static void submodule_collect_changed_cb(struct diff_queue_struct *q,
                         * being moved around. */
                        struct string_list_item *path;
                        path = unsorted_string_list_lookup(&changed_submodule_paths, p->two->path);
-                       if (!path)
+                       if (!path && !is_submodule_commit_present(p->two->path, p->two->sha1))
                                string_list_append(&changed_submodule_paths, xstrdup(p->two->path));
                } else {
                        /* Submodule is new or was moved here */
@@ -380,8 +407,13 @@ int fetch_populated_submodules(int num_options, const char **options,
                        struct string_list_item *fetch_recurse_submodules_option;
                        fetch_recurse_submodules_option = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name);
                        if (fetch_recurse_submodules_option) {
-                               if (!fetch_recurse_submodules_option->util)
+                               if ((intptr_t)fetch_recurse_submodules_option->util == RECURSE_SUBMODULES_OFF)
                                        continue;
+                               if ((intptr_t)fetch_recurse_submodules_option->util == RECURSE_SUBMODULES_ON_DEMAND) {
+                                       if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
+                                               continue;
+                                       default_argv = "on-demand";
+                               }
                        } else {
                                if (config_fetch_recurse_submodules == RECURSE_SUBMODULES_OFF)
                                        continue;