Merge branch 'rs/tag-null-pointer-arith-fix'
[gitweb.git] / submodule.c
index d53181ce7aac81eb42ed30860c909a9814d614da..63e7094e1620c2c3eb7dda0a8c38a833ae2d1c5a 100644 (file)
@@ -69,6 +69,13 @@ int is_staging_gitmodules_ok(const struct index_state *istate)
        return 1;
 }
 
+static int for_each_remote_ref_submodule(const char *submodule,
+                                        each_ref_fn fn, void *cb_data)
+{
+       return refs_for_each_remote_ref(get_submodule_ref_store(submodule),
+                                       fn, cb_data);
+}
+
 /*
  * Try to update the "path" entry in the "submodule.<name>" section of the
  * .gitmodules file. Return 0 only if a .gitmodules file was found, a section
@@ -165,31 +172,18 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
 {
        const struct submodule *submodule = submodule_from_path(&null_oid, path);
        if (submodule) {
-               if (submodule->ignore)
-                       handle_ignore_submodules_arg(diffopt, submodule->ignore);
-               else if (is_gitmodules_unmerged(&the_index))
-                       DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
-       }
-}
+               const char *ignore;
+               char *key;
 
-/* For loading from the .gitmodules file. */
-static int git_modules_config(const char *var, const char *value, void *cb)
-{
-       if (starts_with(var, "submodule."))
-               return parse_submodule_config_option(var, value);
-       return 0;
-}
+               key = xstrfmt("submodule.%s.ignore", submodule->name);
+               if (repo_config_get_string_const(the_repository, key, &ignore))
+                       ignore = submodule->ignore;
+               free(key);
 
-/* Loads all submodule settings from the config. */
-int submodule_config(const char *var, const char *value, void *cb)
-{
-       if (!strcmp(var, "submodule.recurse")) {
-               int v = git_config_bool(var, value) ?
-                       RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
-               config_update_recurse_submodules = v;
-               return 0;
-       } else {
-               return git_modules_config(var, value, cb);
+               if (ignore)
+                       handle_ignore_submodules_arg(diffopt, ignore);
+               else if (is_gitmodules_unmerged(&the_index))
+                       DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
        }
 }
 
@@ -221,55 +215,6 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
        return 0;
 }
 
-void load_submodule_cache(void)
-{
-       if (config_update_recurse_submodules == RECURSE_SUBMODULES_OFF)
-               return;
-
-       gitmodules_config();
-       git_config(submodule_config, NULL);
-}
-
-static int gitmodules_cb(const char *var, const char *value, void *data)
-{
-       struct repository *repo = data;
-       return submodule_config_option(repo, var, value);
-}
-
-void repo_read_gitmodules(struct repository *repo)
-{
-       if (repo->worktree) {
-               char *gitmodules;
-
-               if (repo_read_index(repo) < 0)
-                       return;
-
-               gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
-
-               if (!is_gitmodules_unmerged(repo->index))
-                       git_config_from_file(gitmodules_cb, gitmodules, repo);
-
-               free(gitmodules);
-       }
-}
-
-void gitmodules_config(void)
-{
-       repo_read_gitmodules(the_repository);
-}
-
-void gitmodules_config_oid(const struct object_id *commit_oid)
-{
-       struct strbuf rev = STRBUF_INIT;
-       struct object_id oid;
-
-       if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
-               git_config_from_blob_oid(submodule_config, rev.buf,
-                                        &oid, NULL);
-       }
-       strbuf_release(&rev);
-}
-
 /*
  * Determine if a submodule has been initialized at a given 'path'
  */
@@ -398,24 +343,38 @@ void die_path_inside_submodule(const struct index_state *istate,
        }
 }
 
-int parse_submodule_update_strategy(const char *value,
-               struct submodule_update_strategy *dst)
+enum submodule_update_type parse_submodule_update_type(const char *value)
 {
-       free((void*)dst->command);
-       dst->command = NULL;
        if (!strcmp(value, "none"))
-               dst->type = SM_UPDATE_NONE;
+               return SM_UPDATE_NONE;
        else if (!strcmp(value, "checkout"))
-               dst->type = SM_UPDATE_CHECKOUT;
+               return SM_UPDATE_CHECKOUT;
        else if (!strcmp(value, "rebase"))
-               dst->type = SM_UPDATE_REBASE;
+               return SM_UPDATE_REBASE;
        else if (!strcmp(value, "merge"))
-               dst->type = SM_UPDATE_MERGE;
-       else if (skip_prefix(value, "!", &value)) {
-               dst->type = SM_UPDATE_COMMAND;
-               dst->command = xstrdup(value);
-       } else
+               return SM_UPDATE_MERGE;
+       else if (*value == '!')
+               return SM_UPDATE_COMMAND;
+       else
+               return SM_UPDATE_UNSPECIFIED;
+}
+
+int parse_submodule_update_strategy(const char *value,
+               struct submodule_update_strategy *dst)
+{
+       enum submodule_update_type type;
+
+       free((void*)dst->command);
+       dst->command = NULL;
+
+       type = parse_submodule_update_type(value);
+       if (type == SM_UPDATE_UNSPECIFIED)
                return -1;
+
+       dst->type = type;
+       if (type == SM_UPDATE_COMMAND)
+               dst->command = xstrdup(value + 1);
+
        return 0;
 }
 
@@ -544,7 +503,7 @@ static void show_submodule_header(struct diff_options *o, const char *path,
 
        if (add_submodule_odb(path)) {
                if (!message)
-                       message = "(not initialized)";
+                       message = "(commits not present)";
                goto output_header;
        }
 
@@ -815,19 +774,36 @@ static int append_oid_to_argv(const struct object_id *oid, void *data)
        return 0;
 }
 
+struct has_commit_data {
+       int result;
+       const char *path;
+};
+
 static int check_has_commit(const struct object_id *oid, void *data)
 {
-       int *has_commit = data;
+       struct has_commit_data *cb = data;
 
-       if (!lookup_commit_reference(oid))
-               *has_commit = 0;
+       enum object_type type = sha1_object_info(oid->hash, NULL);
 
-       return 0;
+       switch (type) {
+       case OBJ_COMMIT:
+               return 0;
+       case OBJ_BAD:
+               /*
+                * Object is missing or invalid. If invalid, an error message
+                * has already been printed.
+                */
+               cb->result = 0;
+               return 0;
+       default:
+               die(_("submodule entry '%s' (%s) is a %s, not a commit"),
+                   cb->path, oid_to_hex(oid), typename(type));
+       }
 }
 
 static int submodule_has_commits(const char *path, struct oid_array *commits)
 {
-       int has_commit = 1;
+       struct has_commit_data has_commit = { 1, path };
 
        /*
         * Perform a cheap, but incorrect check for the existence of 'commits'.
@@ -843,7 +819,7 @@ static int submodule_has_commits(const char *path, struct oid_array *commits)
 
        oid_array_for_each_unique(commits, check_has_commit, &has_commit);
 
-       if (has_commit) {
+       if (has_commit.result) {
                /*
                 * Even if the submodule is checked out and the commit is
                 * present, make sure it exists in the submodule's object store
@@ -862,12 +838,12 @@ static int submodule_has_commits(const char *path, struct oid_array *commits)
                cp.dir = path;
 
                if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len)
-                       has_commit = 0;
+                       has_commit.result = 0;
 
                strbuf_release(&out);
        }
 
-       return has_commit;
+       return has_commit.result;
 }
 
 static int submodule_needs_pushing(const char *path, struct oid_array *commits)
@@ -1130,7 +1106,6 @@ int submodule_touches_in_range(struct object_id *excl_oid,
        struct argv_array args = ARGV_ARRAY_INIT;
        int ret;
 
-       gitmodules_config();
        /* No need to check if there are no submodules configured */
        if (!submodule_from_path(NULL, NULL))
                return 0;
@@ -1179,19 +1154,27 @@ static int get_next_submodule(struct child_process *cp,
                        continue;
 
                submodule = submodule_from_path(&null_oid, ce->name);
-               if (!submodule)
-                       submodule = submodule_from_name(&null_oid, ce->name);
 
                default_argv = "yes";
                if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) {
-                       if (submodule &&
-                           submodule->fetch_recurse !=
-                                               RECURSE_SUBMODULES_NONE) {
-                               if (submodule->fetch_recurse ==
-                                               RECURSE_SUBMODULES_OFF)
+                       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);
+                       }
+
+                       if (fetch_recurse != RECURSE_SUBMODULES_NONE) {
+                               if (fetch_recurse == RECURSE_SUBMODULES_OFF)
                                        continue;
-                               if (submodule->fetch_recurse ==
-                                               RECURSE_SUBMODULES_ON_DEMAND) {
+                               if (fetch_recurse == RECURSE_SUBMODULES_ON_DEMAND) {
                                        if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
                                                continue;
                                        default_argv = "on-demand";
@@ -1668,6 +1651,8 @@ static int find_first_merges(struct object_array *result, const char *path,
                        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 */
@@ -1700,7 +1685,7 @@ static int find_first_merges(struct object_array *result, const char *path,
                        add_object_array(merges.objects[i].item, NULL, result);
        }
 
-       free(merges.objects);
+       object_array_clear(&merges);
        return result->nr;
 }
 
@@ -1805,7 +1790,7 @@ int merge_submodule(struct object_id *result, const char *path,
                        print_commit((struct commit *) merges.objects[i].item);
        }
 
-       free(merges.objects);
+       object_array_clear(&merges);
        return 0;
 }
 
@@ -2012,6 +1997,10 @@ const char *get_superproject_working_tree(void)
        return ret;
 }
 
+/*
+ * Put the gitdir for a submodule (given relative to the main
+ * repository worktree) into `buf`, or return -1 on error.
+ */
 int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
 {
        const struct submodule *sub;
@@ -2029,7 +2018,6 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
                strbuf_addstr(buf, git_dir);
        }
        if (!is_git_directory(buf->buf)) {
-               gitmodules_config();
                sub = submodule_from_path(&null_oid, submodule);
                if (!sub) {
                        ret = -1;