subtree test: simplify preparation of expected results
[gitweb.git] / submodule.c
index 63e7094e1620c2c3eb7dda0a8c38a833ae2d1c5a..939d6870ecd7cfbc62f9fa3fb867e5c7362ed9bd 100644 (file)
@@ -1,3 +1,5 @@
+#define NO_THE_INDEX_COMPATIBILITY_MACROS
+
 #include "cache.h"
 #include "repository.h"
 #include "config.h"
 #include "remote.h"
 #include "worktree.h"
 #include "parse-options.h"
+#include "object-store.h"
 
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
-static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP;
+static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP;
 static int initialized_fetch_ref_tips;
 static struct oid_array ref_tips_before_fetch;
 static struct oid_array ref_tips_after_fetch;
@@ -55,14 +58,15 @@ int is_gitmodules_unmerged(const struct index_state *istate)
  * future version when we learn to stage the changes we do ourselves without
  * staging any previous modifications.
  */
-int is_staging_gitmodules_ok(const struct index_state *istate)
+int is_staging_gitmodules_ok(struct index_state *istate)
 {
        int pos = index_name_pos(istate, GITMODULES_FILE, strlen(GITMODULES_FILE));
 
        if ((pos >= 0) && (pos < istate->cache_nr)) {
                struct stat st;
                if (lstat(GITMODULES_FILE, &st) == 0 &&
-                   ce_match_stat(istate->cache[pos], &st, 0) & DATA_CHANGED)
+                   ie_match_stat(istate, istate->cache[pos], &st,
+                                 CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED)
                        return 0;
        }
 
@@ -92,7 +96,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
        if (is_gitmodules_unmerged(&the_index))
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
 
-       submodule = submodule_from_path(&null_oid, oldpath);
+       submodule = submodule_from_path(the_repository, &null_oid, oldpath);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
                return -1;
@@ -126,7 +130,7 @@ int remove_path_from_gitmodules(const char *path)
        if (is_gitmodules_unmerged(&the_index))
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
 
-       submodule = submodule_from_path(&null_oid, path);
+       submodule = submodule_from_path(the_repository, &null_oid, path);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), path);
                return -1;
@@ -143,13 +147,14 @@ int remove_path_from_gitmodules(const char *path)
        return 0;
 }
 
-void stage_updated_gitmodules(void)
+void stage_updated_gitmodules(struct index_state *istate)
 {
-       if (add_file_to_cache(GITMODULES_FILE, 0))
+       if (add_file_to_index(istate, GITMODULES_FILE, 0))
                die(_("staging updated .gitmodules failed"));
 }
 
-static int add_submodule_odb(const char *path)
+/* TODO: remove this function, use repo_submodule_init instead. */
+int add_submodule_odb(const char *path)
 {
        struct strbuf objects_directory = STRBUF_INIT;
        int ret = 0;
@@ -170,7 +175,8 @@ static int add_submodule_odb(const char *path)
 void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                                             const char *path)
 {
-       const struct submodule *submodule = submodule_from_path(&null_oid, path);
+       const struct submodule *submodule = submodule_from_path(the_repository,
+                                                               &null_oid, path);
        if (submodule) {
                const char *ignore;
                char *key;
@@ -183,7 +189,7 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                if (ignore)
                        handle_ignore_submodules_arg(diffopt, ignore);
                else if (is_gitmodules_unmerged(&the_index))
-                       DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
+                       diffopt->flags.ignore_submodules = 1;
        }
 }
 
@@ -226,7 +232,7 @@ int is_submodule_active(struct repository *repo, const char *path)
        const struct string_list *sl;
        const struct submodule *module;
 
-       module = submodule_from_cache(repo, &null_oid, path);
+       module = submodule_from_path(repo, &null_oid, path);
 
        /* early return if there isn't a path->module mapping */
        if (!module)
@@ -402,16 +408,16 @@ const char *submodule_strategy_to_string(const struct submodule_update_strategy
 void handle_ignore_submodules_arg(struct diff_options *diffopt,
                                  const char *arg)
 {
-       DIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES);
-       DIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
-       DIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES);
+       diffopt->flags.ignore_submodules = 0;
+       diffopt->flags.ignore_untracked_in_submodules = 0;
+       diffopt->flags.ignore_dirty_submodules = 0;
 
        if (!strcmp(arg, "all"))
-               DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
+               diffopt->flags.ignore_submodules = 1;
        else if (!strcmp(arg, "untracked"))
-               DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
+               diffopt->flags.ignore_untracked_in_submodules = 1;
        else if (!strcmp(arg, "dirty"))
-               DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);
+               diffopt->flags.ignore_dirty_submodules = 1;
        else if (strcmp(arg, "none"))
                die("bad --ignore-submodules argument: %s", arg);
 }
@@ -537,9 +543,9 @@ static void show_submodule_header(struct diff_options *o, const char *path,
 
 output_header:
        strbuf_addf(&sb, "Submodule %s ", path);
-       strbuf_add_unique_abbrev(&sb, one->hash, DEFAULT_ABBREV);
+       strbuf_add_unique_abbrev(&sb, one, DEFAULT_ABBREV);
        strbuf_addstr(&sb, (fast_backward || fast_forward) ? ".." : "...");
-       strbuf_add_unique_abbrev(&sb, two->hash, DEFAULT_ABBREV);
+       strbuf_add_unique_abbrev(&sb, two, DEFAULT_ABBREV);
        if (message)
                strbuf_addf(&sb, " %s\n", message);
        else
@@ -587,7 +593,7 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
                struct object_id *one, struct object_id *two,
                unsigned dirty_submodule)
 {
-       const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid;
+       const struct object_id *old_oid = the_hash_algo->empty_tree, *new_oid = the_hash_algo->empty_tree;
        struct commit *left = NULL, *right = NULL;
        struct commit_list *merge_bases = NULL;
        struct child_process cp = CHILD_PROCESS_INIT;
@@ -602,9 +608,9 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
                goto done;
 
        if (left)
-               old = one;
+               old_oid = one;
        if (right)
-               new = two;
+               new_oid = two;
 
        cp.git_cmd = 1;
        cp.dir = path;
@@ -616,7 +622,7 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
        argv_array_pushf(&cp.args, "--color=%s", want_color(o->use_color) ?
                         "always" : "never");
 
-       if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+       if (o->flags.reverse_diff) {
                argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
                                 o->b_prefix, path);
                argv_array_pushf(&cp.args, "--dst-prefix=%s%s/",
@@ -627,7 +633,7 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
                argv_array_pushf(&cp.args, "--dst-prefix=%s%s/",
                                 o->b_prefix, path);
        }
-       argv_array_push(&cp.args, oid_to_hex(old));
+       argv_array_push(&cp.args, oid_to_hex(old_oid));
        /*
         * If the submodule has modified content, we will diff against the
         * work tree, under the assumption that the user has asked for the
@@ -635,7 +641,7 @@ void show_submodule_inline_diff(struct diff_options *o, const char *path,
         * haven't yet been committed to the submodule yet.
         */
        if (!(dirty_submodule & DIRTY_SUBMODULE_MODIFIED))
-               argv_array_push(&cp.args, oid_to_hex(new));
+               argv_array_push(&cp.args, oid_to_hex(new_oid));
 
        prepare_submodule_repo_env(&cp.env_array);
        if (start_command(&cp))
@@ -670,15 +676,15 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce)
        if (!should_update_submodules())
                return NULL;
 
-       return submodule_from_path(&null_oid, ce->name);
+       return submodule_from_path(the_repository, &null_oid, ce->name);
 }
 
 static struct oid_array *submodule_commits(struct string_list *submodules,
-                                          const char *path)
+                                          const char *name)
 {
        struct string_list_item *item;
 
-       item = string_list_insert(submodules, path);
+       item = string_list_insert(submodules, name);
        if (item->util)
                return (struct oid_array *) item->util;
 
@@ -687,39 +693,68 @@ static struct oid_array *submodule_commits(struct string_list *submodules,
        return (struct oid_array *) item->util;
 }
 
+struct collect_changed_submodules_cb_data {
+       struct string_list *changed;
+       const struct object_id *commit_oid;
+};
+
+/*
+ * this would normally be two functions: default_name_from_path() and
+ * path_from_default_name(). Since the default name is the same as
+ * the submodule path we can get away with just one function which only
+ * checks whether there is a submodule in the working directory at that
+ * location.
+ */
+static const char *default_name_or_path(const char *path_or_name)
+{
+       int error_code;
+
+       if (!is_submodule_populated_gently(path_or_name, &error_code))
+               return NULL;
+
+       return path_or_name;
+}
+
 static void collect_changed_submodules_cb(struct diff_queue_struct *q,
                                          struct diff_options *options,
                                          void *data)
 {
+       struct collect_changed_submodules_cb_data *me = data;
+       struct string_list *changed = me->changed;
+       const struct object_id *commit_oid = me->commit_oid;
        int i;
-       struct string_list *changed = data;
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
                struct oid_array *commits;
+               const struct submodule *submodule;
+               const char *name;
+
                if (!S_ISGITLINK(p->two->mode))
                        continue;
 
-               if (S_ISGITLINK(p->one->mode)) {
-                       /*
-                        * NEEDSWORK: We should honor the name configured in
-                        * the .gitmodules file of the commit we are examining
-                        * here to be able to correctly follow submodules
-                        * being moved around.
-                        */
-                       commits = submodule_commits(changed, p->two->path);
-                       oid_array_append(commits, &p->two->oid);
-               } else {
-                       /* Submodule is new or was moved here */
-                       /*
-                        * NEEDSWORK: When the .git directories of submodules
-                        * live inside the superprojects .git directory some
-                        * day we should fetch new submodules directly into
-                        * that location too when config or options request
-                        * that so they can be checked out from there.
-                        */
-                       continue;
+               submodule = submodule_from_path(the_repository,
+                                               commit_oid, p->two->path);
+               if (submodule)
+                       name = submodule->name;
+               else {
+                       name = default_name_or_path(p->two->path);
+                       /* make sure name does not collide with existing one */
+                       submodule = submodule_from_name(the_repository, commit_oid, name);
+                       if (submodule) {
+                               warning("Submodule in commit %s at path: "
+                                       "'%s' collides with a submodule named "
+                                       "the same. Skipping it.",
+                                       oid_to_hex(commit_oid), name);
+                               name = NULL;
+                       }
                }
+
+               if (!name)
+                       continue;
+
+               commits = submodule_commits(changed, name);
+               oid_array_append(commits, &p->two->oid);
        }
 }
 
@@ -742,11 +777,14 @@ static void collect_changed_submodules(struct string_list *changed,
 
        while ((commit = get_revision(&rev))) {
                struct rev_info diff_rev;
+               struct collect_changed_submodules_cb_data data;
+               data.changed = changed;
+               data.commit_oid = &commit->object.oid;
 
                init_revisions(&diff_rev, NULL);
                diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
                diff_rev.diffopt.format_callback = collect_changed_submodules_cb;
-               diff_rev.diffopt.format_callback_data = changed;
+               diff_rev.diffopt.format_callback_data = &data;
                diff_tree_combined_merge(commit, 1, &diff_rev);
        }
 
@@ -783,7 +821,7 @@ static int check_has_commit(const struct object_id *oid, void *data)
 {
        struct has_commit_data *cb = data;
 
-       enum object_type type = sha1_object_info(oid->hash, NULL);
+       enum object_type type = oid_object_info(the_repository, oid, NULL);
 
        switch (type) {
        case OBJ_COMMIT:
@@ -797,7 +835,7 @@ static int check_has_commit(const struct object_id *oid, void *data)
                return 0;
        default:
                die(_("submodule entry '%s' (%s) is a %s, not a commit"),
-                   cb->path, oid_to_hex(oid), typename(type));
+                   cb->path, oid_to_hex(oid), type_name(type));
        }
 }
 
@@ -894,7 +932,7 @@ int find_unpushed_submodules(struct oid_array *commits,
                const char *remotes_name, struct string_list *needs_pushing)
 {
        struct string_list submodules = STRING_LIST_INIT_DUP;
-       struct string_list_item *submodule;
+       struct string_list_item *name;
        struct argv_array argv = ARGV_ARRAY_INIT;
 
        /* argv.argv[0] will be ignored by setup_revisions */
@@ -905,9 +943,19 @@ int find_unpushed_submodules(struct oid_array *commits,
 
        collect_changed_submodules(&submodules, &argv);
 
-       for_each_string_list_item(submodule, &submodules) {
-               struct oid_array *commits = submodule->util;
-               const char *path = submodule->string;
+       for_each_string_list_item(name, &submodules) {
+               struct oid_array *commits = name->util;
+               const struct submodule *submodule;
+               const char *path = NULL;
+
+               submodule = submodule_from_name(the_repository, &null_oid, name->string);
+               if (submodule)
+                       path = submodule->path;
+               else
+                       path = default_name_or_path(name->string);
+
+               if (!path)
+                       continue;
 
                if (submodule_needs_pushing(path, commits))
                        string_list_insert(needs_pushing, path);
@@ -921,7 +969,7 @@ int find_unpushed_submodules(struct oid_array *commits,
 
 static int push_submodule(const char *path,
                          const struct remote *remote,
-                         const char **refspec, int refspec_nr,
+                         const struct refspec *rs,
                          const struct string_list *push_options,
                          int dry_run)
 {
@@ -944,8 +992,8 @@ static int push_submodule(const char *path,
                if (remote->origin != REMOTE_UNCONFIGURED) {
                        int i;
                        argv_array_push(&cp.args, remote->name);
-                       for (i = 0; i < refspec_nr; i++)
-                               argv_array_push(&cp.args, refspec[i]);
+                       for (i = 0; i < rs->raw_nr; i++)
+                               argv_array_push(&cp.args, rs->raw[i]);
                }
 
                prepare_submodule_repo_env(&cp.env_array);
@@ -966,7 +1014,7 @@ static int push_submodule(const char *path,
  */
 static void submodule_push_check(const char *path, const char *head,
                                 const struct remote *remote,
-                                const char **refspec, int refspec_nr)
+                                const struct refspec *rs)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
        int i;
@@ -976,8 +1024,8 @@ static void submodule_push_check(const char *path, const char *head,
        argv_array_push(&cp.args, head);
        argv_array_push(&cp.args, remote->name);
 
-       for (i = 0; i < refspec_nr; i++)
-               argv_array_push(&cp.args, refspec[i]);
+       for (i = 0; i < rs->raw_nr; i++)
+               argv_array_push(&cp.args, rs->raw[i]);
 
        prepare_submodule_repo_env(&cp.env_array);
        cp.git_cmd = 1;
@@ -996,7 +1044,7 @@ static void submodule_push_check(const char *path, const char *head,
 
 int push_unpushed_submodules(struct oid_array *commits,
                             const struct remote *remote,
-                            const char **refspec, int refspec_nr,
+                            const struct refspec *rs,
                             const struct string_list *push_options,
                             int dry_run)
 {
@@ -1016,14 +1064,13 @@ int push_unpushed_submodules(struct oid_array *commits,
                char *head;
                struct object_id head_oid;
 
-               head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+               head = resolve_refdup("HEAD", 0, &head_oid, NULL);
                if (!head)
                        die(_("Failed to resolve HEAD as a valid ref."));
 
                for (i = 0; i < needs_pushing.nr; i++)
                        submodule_push_check(needs_pushing.items[i].string,
-                                            head, remote,
-                                            refspec, refspec_nr);
+                                            head, remote, rs);
                free(head);
        }
 
@@ -1031,7 +1078,7 @@ int push_unpushed_submodules(struct oid_array *commits,
        for (i = 0; i < needs_pushing.nr; i++) {
                const char *path = needs_pushing.items[i].string;
                fprintf(stderr, "Pushing submodule '%s'\n", path);
-               if (!push_submodule(path, remote, refspec, refspec_nr,
+               if (!push_submodule(path, remote, rs,
                                    push_options, dry_run)) {
                        fprintf(stderr, "Unable to push submodule '%s'\n", path);
                        ret = 0;
@@ -1065,10 +1112,10 @@ static void calculate_changed_submodule_paths(void)
 {
        struct argv_array argv = ARGV_ARRAY_INIT;
        struct string_list changed_submodules = STRING_LIST_INIT_DUP;
-       const struct string_list_item *item;
+       const struct string_list_item *name;
 
        /* No need to check if there are no submodules configured */
-       if (!submodule_from_path(NULL, NULL))
+       if (!submodule_from_path(the_repository, NULL, NULL))
                return;
 
        argv_array_push(&argv, "--"); /* argv[0] program name */
@@ -1080,16 +1127,26 @@ static void calculate_changed_submodule_paths(void)
 
        /*
         * Collect all submodules (whether checked out or not) for which new
-        * commits have been recorded upstream in "changed_submodule_paths".
+        * commits have been recorded upstream in "changed_submodule_names".
         */
        collect_changed_submodules(&changed_submodules, &argv);
 
-       for_each_string_list_item(item, &changed_submodules) {
-               struct oid_array *commits = item->util;
-               const char *path = item->string;
+       for_each_string_list_item(name, &changed_submodules) {
+               struct oid_array *commits = name->util;
+               const struct submodule *submodule;
+               const char *path = NULL;
+
+               submodule = submodule_from_name(the_repository, &null_oid, name->string);
+               if (submodule)
+                       path = submodule->path;
+               else
+                       path = default_name_or_path(name->string);
+
+               if (!path)
+                       continue;
 
                if (!submodule_has_commits(path, commits))
-                       string_list_append(&changed_submodule_paths, path);
+                       string_list_append(&changed_submodule_names, name->string);
        }
 
        free_submodules_oids(&changed_submodules);
@@ -1107,13 +1164,15 @@ int submodule_touches_in_range(struct object_id *excl_oid,
        int ret;
 
        /* No need to check if there are no submodules configured */
-       if (!submodule_from_path(NULL, NULL))
+       if (!submodule_from_path(the_repository, NULL, NULL))
                return 0;
 
        argv_array_push(&args, "--"); /* args[0] program name */
        argv_array_push(&args, oid_to_hex(incl_oid));
-       argv_array_push(&args, "--not");
-       argv_array_push(&args, oid_to_hex(excl_oid));
+       if (!is_null_oid(excl_oid)) {
+               argv_array_push(&args, "--not");
+               argv_array_push(&args, oid_to_hex(excl_oid));
+       }
 
        collect_changed_submodules(&subs, &args);
        ret = subs.nr;
@@ -1127,7 +1186,7 @@ int submodule_touches_in_range(struct object_id *excl_oid,
 struct submodule_parallel_fetch {
        int count;
        struct argv_array args;
-       const char *work_tree;
+       struct repository *r;
        const char *prefix;
        int command_line_option;
        int default_option;
@@ -1136,65 +1195,76 @@ struct submodule_parallel_fetch {
 };
 #define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0}
 
+static int get_fetch_recurse_config(const struct submodule *submodule,
+                                   struct submodule_parallel_fetch *spf)
+{
+       if (spf->command_line_option != RECURSE_SUBMODULES_DEFAULT)
+               return spf->command_line_option;
+
+       if (submodule) {
+               char *key;
+               const char *value;
+
+               int fetch_recurse = submodule->fetch_recurse;
+               key = xstrfmt("submodule.%s.fetchRecurseSubmodules", submodule->name);
+               if (!repo_config_get_string_const(spf->r, key, &value)) {
+                       fetch_recurse = parse_fetch_recurse_submodules_arg(key, value);
+               }
+               free(key);
+
+               if (fetch_recurse != RECURSE_SUBMODULES_NONE)
+                       /* local config overrules everything except commandline */
+                       return fetch_recurse;
+       }
+
+       return spf->default_option;
+}
+
 static int get_next_submodule(struct child_process *cp,
                              struct strbuf *err, void *data, void **task_cb)
 {
        int ret = 0;
        struct submodule_parallel_fetch *spf = data;
 
-       for (; spf->count < active_nr; spf->count++) {
+       for (; spf->count < spf->r->index->cache_nr; spf->count++) {
                struct strbuf submodule_path = STRBUF_INIT;
                struct strbuf submodule_git_dir = STRBUF_INIT;
                struct strbuf submodule_prefix = STRBUF_INIT;
-               const struct cache_entry *ce = active_cache[spf->count];
+               const struct cache_entry *ce = spf->r->index->cache[spf->count];
                const char *git_dir, *default_argv;
                const struct submodule *submodule;
+               struct submodule default_submodule = SUBMODULE_INIT;
 
                if (!S_ISGITLINK(ce->ce_mode))
                        continue;
 
-               submodule = submodule_from_path(&null_oid, ce->name);
-
-               default_argv = "yes";
-               if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) {
-                       int fetch_recurse = RECURSE_SUBMODULES_NONE;
-
-                       if (submodule) {
-                               char *key;
-                               const char *value;
-
-                               fetch_recurse = submodule->fetch_recurse;
-                               key = xstrfmt("submodule.%s.fetchRecurseSubmodules", submodule->name);
-                               if (!repo_config_get_string_const(the_repository, key, &value)) {
-                                       fetch_recurse = parse_fetch_recurse_submodules_arg(key, value);
-                               }
-                               free(key);
+               submodule = submodule_from_path(spf->r, &null_oid, ce->name);
+               if (!submodule) {
+                       const char *name = default_name_or_path(ce->name);
+                       if (name) {
+                               default_submodule.path = default_submodule.name = name;
+                               submodule = &default_submodule;
                        }
+               }
 
-                       if (fetch_recurse != RECURSE_SUBMODULES_NONE) {
-                               if (fetch_recurse == RECURSE_SUBMODULES_OFF)
-                                       continue;
-                               if (fetch_recurse == RECURSE_SUBMODULES_ON_DEMAND) {
-                                       if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
-                                               continue;
-                                       default_argv = "on-demand";
-                               }
-                       } else {
-                               if (spf->default_option == RECURSE_SUBMODULES_OFF)
-                                       continue;
-                               if (spf->default_option == RECURSE_SUBMODULES_ON_DEMAND) {
-                                       if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
-                                               continue;
-                                       default_argv = "on-demand";
-                               }
-                       }
-               } else if (spf->command_line_option == RECURSE_SUBMODULES_ON_DEMAND) {
-                       if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
+               switch (get_fetch_recurse_config(submodule, spf))
+               {
+               default:
+               case RECURSE_SUBMODULES_DEFAULT:
+               case RECURSE_SUBMODULES_ON_DEMAND:
+                       if (!submodule || !unsorted_string_list_lookup(&changed_submodule_names,
+                                                        submodule->name))
                                continue;
                        default_argv = "on-demand";
+                       break;
+               case RECURSE_SUBMODULES_ON:
+                       default_argv = "yes";
+                       break;
+               case RECURSE_SUBMODULES_OFF:
+                       continue;
                }
 
-               strbuf_addf(&submodule_path, "%s/%s", spf->work_tree, ce->name);
+               strbuf_repo_worktree_path(&submodule_path, spf->r, "%s", ce->name);
                strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf);
                strbuf_addf(&submodule_prefix, "%s%s/", spf->prefix, ce->name);
                git_dir = read_gitfile(submodule_git_dir.buf);
@@ -1247,7 +1317,8 @@ static int fetch_finish(int retvalue, struct strbuf *err,
        return 0;
 }
 
-int fetch_populated_submodules(const struct argv_array *options,
+int fetch_populated_submodules(struct repository *r,
+                              const struct argv_array *options,
                               const char *prefix, int command_line_option,
                               int default_option,
                               int quiet, int max_parallel_jobs)
@@ -1255,16 +1326,16 @@ int fetch_populated_submodules(const struct argv_array *options,
        int i;
        struct submodule_parallel_fetch spf = SPF_INIT;
 
-       spf.work_tree = get_git_work_tree();
+       spf.r = r;
        spf.command_line_option = command_line_option;
        spf.default_option = default_option;
        spf.quiet = quiet;
        spf.prefix = prefix;
 
-       if (!spf.work_tree)
+       if (!r->worktree)
                goto out;
 
-       if (read_cache() < 0)
+       if (repo_read_index(r) < 0)
                die("index file corrupt");
 
        argv_array_push(&spf.args, "fetch");
@@ -1282,7 +1353,7 @@ int fetch_populated_submodules(const struct argv_array *options,
 
        argv_array_clear(&spf.args);
 out:
-       string_list_clear(&changed_submodule_paths, 1);
+       string_list_clear(&changed_submodule_names, 1);
        return spf.result;
 }
 
@@ -1331,7 +1402,7 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
                    buf.buf[0] == '2') {
                        /* T = line type, XY = status, SSSS = submodule state */
                        if (buf.len < strlen("T XY SSSS"))
-                               die("BUG: invalid status --porcelain=2 line %s",
+                               BUG("invalid status --porcelain=2 line %s",
                                    buf.buf);
 
                        if (buf.buf[5] == 'S' && buf.buf[8] == 'U')
@@ -1500,7 +1571,7 @@ static void submodule_reset_index(const char *path)
                                   get_super_prefix_or_empty(), path);
        argv_array_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
 
-       argv_array_push(&cp.args, EMPTY_TREE_SHA1_HEX);
+       argv_array_push(&cp.args, empty_tree_oid_hex());
 
        if (run_command(&cp))
                die("could not reset submodule index");
@@ -1512,8 +1583,8 @@ static void submodule_reset_index(const char *path)
  * pass NULL for old or new respectively.
  */
 int submodule_move_head(const char *path,
-                        const char *old,
-                        const char *new,
+                        const char *old_head,
+                        const char *new_head,
                         unsigned flags)
 {
        int ret = 0;
@@ -1534,39 +1605,39 @@ int submodule_move_head(const char *path,
        else
                error_code_ptr = NULL;
 
-       if (old && !is_submodule_populated_gently(path, error_code_ptr))
+       if (old_head && !is_submodule_populated_gently(path, error_code_ptr))
                return 0;
 
-       sub = submodule_from_path(&null_oid, path);
+       sub = submodule_from_path(the_repository, &null_oid, path);
 
        if (!sub)
-               die("BUG: could not get submodule information for '%s'", path);
+               BUG("could not get submodule information for '%s'", path);
 
-       if (old && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) {
+       if (old_head && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) {
                /* Check if the submodule has a dirty index. */
                if (submodule_has_dirty_index(sub))
                        return error(_("submodule '%s' has dirty index"), path);
        }
 
        if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
-               if (old) {
+               if (old_head) {
                        if (!submodule_uses_gitfile(path))
                                absorb_git_dir_into_superproject("", path,
                                        ABSORB_GITDIR_RECURSE_SUBMODULES);
                } else {
                        char *gitdir = xstrfmt("%s/modules/%s",
                                    get_git_common_dir(), sub->name);
-                       connect_work_tree_and_git_dir(path, gitdir);
+                       connect_work_tree_and_git_dir(path, gitdir, 0);
                        free(gitdir);
 
                        /* make sure the index is clean as well */
                        submodule_reset_index(path);
                }
 
-               if (old && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
+               if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
                        char *gitdir = xstrfmt("%s/modules/%s",
                                    get_git_common_dir(), sub->name);
-                       connect_work_tree_and_git_dir(path, gitdir);
+                       connect_work_tree_and_git_dir(path, gitdir, 1);
                        free(gitdir);
                }
        }
@@ -1591,8 +1662,10 @@ int submodule_move_head(const char *path,
        else
                argv_array_push(&cp.args, "-m");
 
-       argv_array_push(&cp.args, old ? old : EMPTY_TREE_SHA1_HEX);
-       argv_array_push(&cp.args, new ? new : EMPTY_TREE_SHA1_HEX);
+       if (!(flags & SUBMODULE_MOVE_HEAD_FORCE))
+               argv_array_push(&cp.args, old_head ? old_head : empty_tree_oid_hex());
+
+       argv_array_push(&cp.args, new_head ? new_head : empty_tree_oid_hex());
 
        if (run_command(&cp)) {
                ret = -1;
@@ -1600,7 +1673,7 @@ int submodule_move_head(const char *path,
        }
 
        if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
-               if (new) {
+               if (new_head) {
                        child_process_init(&cp);
                        /* also set the HEAD accordingly */
                        cp.git_cmd = 1;
@@ -1608,7 +1681,8 @@ int submodule_move_head(const char *path,
                        cp.dir = path;
 
                        prepare_submodule_repo_env(&cp.env_array);
-                       argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL);
+                       argv_array_pushl(&cp.args, "update-ref", "HEAD",
+                                        "--no-deref", new_head, NULL);
 
                        if (run_command(&cp)) {
                                ret = -1;
@@ -1629,171 +1703,6 @@ int submodule_move_head(const char *path,
        return ret;
 }
 
-static int find_first_merges(struct object_array *result, const char *path,
-               struct commit *a, struct commit *b)
-{
-       int i, j;
-       struct object_array merges = OBJECT_ARRAY_INIT;
-       struct commit *commit;
-       int contains_another;
-
-       char merged_revision[42];
-       const char *rev_args[] = { "rev-list", "--merges", "--ancestry-path",
-                                  "--all", merged_revision, NULL };
-       struct rev_info revs;
-       struct setup_revision_opt rev_opts;
-
-       memset(result, 0, sizeof(struct object_array));
-       memset(&rev_opts, 0, sizeof(rev_opts));
-
-       /* get all revisions that merge commit a */
-       xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
-                       oid_to_hex(&a->object.oid));
-       init_revisions(&revs, NULL);
-       rev_opts.submodule = path;
-       /* FIXME: can't handle linked worktrees in submodules yet */
-       revs.single_worktree = path != NULL;
-       setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);
-
-       /* save all revisions from the above list that contain b */
-       if (prepare_revision_walk(&revs))
-               die("revision walk setup failed");
-       while ((commit = get_revision(&revs)) != NULL) {
-               struct object *o = &(commit->object);
-               if (in_merge_bases(b, commit))
-                       add_object_array(o, NULL, &merges);
-       }
-       reset_revision_walk();
-
-       /* Now we've got all merges that contain a and b. Prune all
-        * merges that contain another found merge and save them in
-        * result.
-        */
-       for (i = 0; i < merges.nr; i++) {
-               struct commit *m1 = (struct commit *) merges.objects[i].item;
-
-               contains_another = 0;
-               for (j = 0; j < merges.nr; j++) {
-                       struct commit *m2 = (struct commit *) merges.objects[j].item;
-                       if (i != j && in_merge_bases(m2, m1)) {
-                               contains_another = 1;
-                               break;
-                       }
-               }
-
-               if (!contains_another)
-                       add_object_array(merges.objects[i].item, NULL, result);
-       }
-
-       object_array_clear(&merges);
-       return result->nr;
-}
-
-static void print_commit(struct commit *commit)
-{
-       struct strbuf sb = STRBUF_INIT;
-       struct pretty_print_context ctx = {0};
-       ctx.date_mode.type = DATE_NORMAL;
-       format_commit_message(commit, " %h: %m %s", &sb, &ctx);
-       fprintf(stderr, "%s\n", sb.buf);
-       strbuf_release(&sb);
-}
-
-#define MERGE_WARNING(path, msg) \
-       warning("Failed to merge submodule %s (%s)", path, msg);
-
-int merge_submodule(struct object_id *result, const char *path,
-                   const struct object_id *base, const struct object_id *a,
-                   const struct object_id *b, int search)
-{
-       struct commit *commit_base, *commit_a, *commit_b;
-       int parent_count;
-       struct object_array merges;
-
-       int i;
-
-       /* store a in result in case we fail */
-       oidcpy(result, a);
-
-       /* we can not handle deletion conflicts */
-       if (is_null_oid(base))
-               return 0;
-       if (is_null_oid(a))
-               return 0;
-       if (is_null_oid(b))
-               return 0;
-
-       if (add_submodule_odb(path)) {
-               MERGE_WARNING(path, "not checked out");
-               return 0;
-       }
-
-       if (!(commit_base = lookup_commit_reference(base)) ||
-           !(commit_a = lookup_commit_reference(a)) ||
-           !(commit_b = lookup_commit_reference(b))) {
-               MERGE_WARNING(path, "commits not present");
-               return 0;
-       }
-
-       /* check whether both changes are forward */
-       if (!in_merge_bases(commit_base, commit_a) ||
-           !in_merge_bases(commit_base, commit_b)) {
-               MERGE_WARNING(path, "commits don't follow merge-base");
-               return 0;
-       }
-
-       /* Case #1: a is contained in b or vice versa */
-       if (in_merge_bases(commit_a, commit_b)) {
-               oidcpy(result, b);
-               return 1;
-       }
-       if (in_merge_bases(commit_b, commit_a)) {
-               oidcpy(result, a);
-               return 1;
-       }
-
-       /*
-        * Case #2: There are one or more merges that contain a and b in
-        * the submodule. If there is only one, then present it as a
-        * suggestion to the user, but leave it marked unmerged so the
-        * user needs to confirm the resolution.
-        */
-
-       /* Skip the search if makes no sense to the calling context.  */
-       if (!search)
-               return 0;
-
-       /* find commit which merges them */
-       parent_count = find_first_merges(&merges, path, commit_a, commit_b);
-       switch (parent_count) {
-       case 0:
-               MERGE_WARNING(path, "merge following commits not found");
-               break;
-
-       case 1:
-               MERGE_WARNING(path, "not fast-forward");
-               fprintf(stderr, "Found a possible merge resolution "
-                               "for the submodule:\n");
-               print_commit((struct commit *) merges.objects[0].item);
-               fprintf(stderr,
-                       "If this is correct simply add it to the index "
-                       "for example\n"
-                       "by using:\n\n"
-                       "  git update-index --cacheinfo 160000 %s \"%s\"\n\n"
-                       "which will accept this suggestion.\n",
-                       oid_to_hex(&merges.objects[0].item->oid), path);
-               break;
-
-       default:
-               MERGE_WARNING(path, "multiple merges found");
-               for (i = 0; i < merges.nr; i++)
-                       print_commit((struct commit *) merges.objects[i].item);
-       }
-
-       object_array_clear(&merges);
-       return 0;
-}
-
 /*
  * Embeds a single submodules git directory into the superprojects git dir,
  * non recursively.
@@ -1816,7 +1725,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
 
        real_old_git_dir = real_pathdup(old_git_dir, 1);
 
-       sub = submodule_from_path(&null_oid, path);
+       sub = submodule_from_path(the_repository, &null_oid, path);
        if (!sub)
                die(_("could not lookup name for submodule '%s'"), path);
 
@@ -1872,11 +1781,11 @@ void absorb_git_dir_into_superproject(const char *prefix,
                * superproject did not rewrite the git file links yet,
                * fix it now.
                */
-               sub = submodule_from_path(&null_oid, path);
+               sub = submodule_from_path(the_repository, &null_oid, path);
                if (!sub)
                        die(_("could not lookup name for submodule '%s'"), path);
                connect_work_tree_and_git_dir(path,
-                       git_path("modules/%s", sub->name));
+                       git_path("modules/%s", sub->name), 0);
        } else {
                /* Is it already absorbed into the superprojects git dir? */
                char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
@@ -1895,7 +1804,7 @@ void absorb_git_dir_into_superproject(const char *prefix,
                struct strbuf sb = STRBUF_INIT;
 
                if (flags & ~ABSORB_GITDIR_RECURSE_SUBMODULES)
-                       die("BUG: we don't know how to pass the flags down?");
+                       BUG("we don't know how to pass the flags down?");
 
                strbuf_addstr(&sb, get_super_prefix_or_empty());
                strbuf_addstr(&sb, path);
@@ -1973,7 +1882,7 @@ const char *get_superproject_working_tree(void)
 
                if (super_sub_len > cwd_len ||
                    strcmp(&cwd[cwd_len - super_sub_len], super_sub))
-                       die (_("BUG: returned path string doesn't match cwd?"));
+                       BUG("returned path string doesn't match cwd?");
 
                super_wt = xstrdup(cwd);
                super_wt[cwd_len - super_sub_len] = '\0';
@@ -2018,7 +1927,7 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
                strbuf_addstr(buf, git_dir);
        }
        if (!is_git_directory(buf->buf)) {
-               sub = submodule_from_path(&null_oid, submodule);
+               sub = submodule_from_path(the_repository, &null_oid, submodule);
                if (!sub) {
                        ret = -1;
                        goto cleanup;