Merge branch 'jk/unavailable-can-be-missing'
[gitweb.git] / submodule.c
index 239d94d5394a318d1a36c3300981e34427928dd7..eb08cf0782ad13d2629c54b8154f4afe78bd0650 100644 (file)
@@ -1,3 +1,5 @@
+#define NO_THE_INDEX_COMPATIBILITY_MACROS
+
 #include "cache.h"
 #include "repository.h"
 #include "config.h"
@@ -19,6 +21,7 @@
 #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_names = STRING_LIST_INIT_DUP;
@@ -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,9 +147,9 @@ 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"));
 }
 
@@ -170,7 +174,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 +188,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 +231,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 +407,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 +542,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 +592,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 +607,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 +621,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 +632,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 +640,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,7 +675,7 @@ 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,
@@ -727,13 +732,14 @@ static void collect_changed_submodules_cb(struct diff_queue_struct *q,
                if (!S_ISGITLINK(p->two->mode))
                        continue;
 
-               submodule = submodule_from_path(commit_oid, p->two->path);
+               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(commit_oid, name);
+                       submodule = submodule_from_name(the_repository, commit_oid, name);
                        if (submodule) {
                                warning("Submodule in commit %s at path: "
                                        "'%s' collides with a submodule named "
@@ -814,7 +820,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:
@@ -828,7 +834,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));
        }
 }
 
@@ -941,7 +947,7 @@ int find_unpushed_submodules(struct oid_array *commits,
                const struct submodule *submodule;
                const char *path = NULL;
 
-               submodule = submodule_from_name(&null_oid, name->string);
+               submodule = submodule_from_name(the_repository, &null_oid, name->string);
                if (submodule)
                        path = submodule->path;
                else
@@ -1109,7 +1115,7 @@ static void calculate_changed_submodule_paths(void)
        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 */
@@ -1130,7 +1136,7 @@ static void calculate_changed_submodule_paths(void)
                const struct submodule *submodule;
                const char *path = NULL;
 
-               submodule = submodule_from_name(&null_oid, name->string);
+               submodule = submodule_from_name(the_repository, &null_oid, name->string);
                if (submodule)
                        path = submodule->path;
                else
@@ -1158,7 +1164,7 @@ 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 */
@@ -1178,7 +1184,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;
@@ -1199,7 +1205,7 @@ static int get_fetch_recurse_config(const struct submodule *submodule,
 
                int fetch_recurse = submodule->fetch_recurse;
                key = xstrfmt("submodule.%s.fetchRecurseSubmodules", submodule->name);
-               if (!repo_config_get_string_const(the_repository, key, &value)) {
+               if (!repo_config_get_string_const(spf->r, key, &value)) {
                        fetch_recurse = parse_fetch_recurse_submodules_arg(key, value);
                }
                free(key);
@@ -1218,11 +1224,11 @@ static int get_next_submodule(struct child_process *cp,
        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;
@@ -1230,7 +1236,7 @@ static int get_next_submodule(struct child_process *cp,
                if (!S_ISGITLINK(ce->ce_mode))
                        continue;
 
-               submodule = submodule_from_path(&null_oid, ce->name);
+               submodule = submodule_from_path(spf->r, &null_oid, ce->name);
                if (!submodule) {
                        const char *name = default_name_or_path(ce->name);
                        if (name) {
@@ -1256,7 +1262,7 @@ static int get_next_submodule(struct child_process *cp,
                        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);
@@ -1309,7 +1315,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)
@@ -1317,16 +1324,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");
@@ -1393,7 +1400,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')
@@ -1574,8 +1581,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;
@@ -1596,39 +1603,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);
                }
        }
@@ -1653,8 +1660,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_SHA1_HEX);
+
+       argv_array_push(&cp.args, new_head ? new_head : EMPTY_TREE_SHA1_HEX);
 
        if (run_command(&cp)) {
                ret = -1;
@@ -1662,7 +1671,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;
@@ -1670,7 +1679,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;
@@ -1878,7 +1888,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);
 
@@ -1934,11 +1944,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);
@@ -1957,7 +1967,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);
@@ -2035,7 +2045,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';
@@ -2080,7 +2090,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;