Merge branch 'mk/describe-match-with-all'
[gitweb.git] / submodule.c
index 8a9b964ce8565b7b7d5bcaa668a54ba4c852514d..b12600fc798f4427c8ad3bff1384c6fb5a6f4bc5 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'
  */
@@ -492,9 +437,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
        return prepare_revision_walk(rev);
 }
 
-static void print_submodule_summary(struct rev_info *rev, FILE *f,
-               const char *line_prefix,
-               const char *del, const char *add, const char *reset)
+static void print_submodule_summary(struct rev_info *rev, struct diff_options *o)
 {
        static const char format[] = "  %m %s";
        struct strbuf sb = STRBUF_INIT;
@@ -505,18 +448,12 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,
                ctx.date_mode = rev->date_mode;
                ctx.output_encoding = get_log_output_encoding();
                strbuf_setlen(&sb, 0);
-               strbuf_addstr(&sb, line_prefix);
-               if (commit->object.flags & SYMMETRIC_LEFT) {
-                       if (del)
-                               strbuf_addstr(&sb, del);
-               }
-               else if (add)
-                       strbuf_addstr(&sb, add);
                format_commit_message(commit, format, &sb, &ctx);
-               if (reset)
-                       strbuf_addstr(&sb, reset);
                strbuf_addch(&sb, '\n');
-               fprintf(f, "%s", sb.buf);
+               if (commit->object.flags & SYMMETRIC_LEFT)
+                       diff_emit_submodule_del(o, sb.buf);
+               else
+                       diff_emit_submodule_add(o, sb.buf);
        }
        strbuf_release(&sb);
 }
@@ -543,11 +480,9 @@ void prepare_submodule_repo_env(struct argv_array *out)
  * attempt to lookup both the left and right commits and put them into the
  * left and right pointers.
  */
-static void show_submodule_header(FILE *f, const char *path,
-               const char *line_prefix,
+static void show_submodule_header(struct diff_options *o, const char *path,
                struct object_id *one, struct object_id *two,
-               unsigned dirty_submodule, const char *meta,
-               const char *reset,
+               unsigned dirty_submodule,
                struct commit **left, struct commit **right,
                struct commit_list **merge_bases)
 {
@@ -556,11 +491,10 @@ static void show_submodule_header(FILE *f, const char *path,
        int fast_forward = 0, fast_backward = 0;
 
        if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
-               fprintf(f, "%sSubmodule %s contains untracked content\n",
-                       line_prefix, path);
+               diff_emit_submodule_untracked(o, path);
+
        if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
-               fprintf(f, "%sSubmodule %s contains modified content\n",
-                       line_prefix, path);
+               diff_emit_submodule_modified(o, path);
 
        if (is_null_oid(one))
                message = "(new submodule)";
@@ -602,31 +536,29 @@ static void show_submodule_header(FILE *f, const char *path,
        }
 
 output_header:
-       strbuf_addf(&sb, "%s%sSubmodule %s ", line_prefix, meta, path);
+       strbuf_addf(&sb, "Submodule %s ", path);
        strbuf_add_unique_abbrev(&sb, one->hash, DEFAULT_ABBREV);
        strbuf_addstr(&sb, (fast_backward || fast_forward) ? ".." : "...");
        strbuf_add_unique_abbrev(&sb, two->hash, DEFAULT_ABBREV);
        if (message)
-               strbuf_addf(&sb, " %s%s\n", message, reset);
+               strbuf_addf(&sb, " %s\n", message);
        else
-               strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset);
-       fwrite(sb.buf, sb.len, 1, f);
+               strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
+       diff_emit_submodule_header(o, sb.buf);
 
        strbuf_release(&sb);
 }
 
-void show_submodule_summary(FILE *f, const char *path,
-               const char *line_prefix,
+void show_submodule_summary(struct diff_options *o, const char *path,
                struct object_id *one, struct object_id *two,
-               unsigned dirty_submodule, const char *meta,
-               const char *del, const char *add, const char *reset)
+               unsigned dirty_submodule)
 {
        struct rev_info rev;
        struct commit *left = NULL, *right = NULL;
        struct commit_list *merge_bases = NULL;
 
-       show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
-                             meta, reset, &left, &right, &merge_bases);
+       show_submodule_header(o, path, one, two, dirty_submodule,
+                             &left, &right, &merge_bases);
 
        /*
         * If we don't have both a left and a right pointer, there is no
@@ -638,11 +570,11 @@ void show_submodule_summary(FILE *f, const char *path,
 
        /* Treat revision walker failure the same as missing commits */
        if (prepare_submodule_summary(&rev, path, left, right, merge_bases)) {
-               fprintf(f, "%s(revision walker failed)\n", line_prefix);
+               diff_emit_submodule_error(o, "(revision walker failed)\n");
                goto out;
        }
 
-       print_submodule_summary(&rev, f, line_prefix, del, add, reset);
+       print_submodule_summary(&rev, o);
 
 out:
        if (merge_bases)
@@ -651,21 +583,18 @@ void show_submodule_summary(FILE *f, const char *path,
        clear_commit_marks(right, ~0);
 }
 
-void show_submodule_inline_diff(FILE *f, const char *path,
-               const char *line_prefix,
+void show_submodule_inline_diff(struct diff_options *o, const char *path,
                struct object_id *one, struct object_id *two,
-               unsigned dirty_submodule, const char *meta,
-               const char *del, const char *add, const char *reset,
-               const struct diff_options *o)
+               unsigned dirty_submodule)
 {
        const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid;
        struct commit *left = NULL, *right = NULL;
        struct commit_list *merge_bases = NULL;
-       struct strbuf submodule_dir = STRBUF_INIT;
        struct child_process cp = CHILD_PROCESS_INIT;
+       struct strbuf sb = STRBUF_INIT;
 
-       show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
-                             meta, reset, &left, &right, &merge_bases);
+       show_submodule_header(o, path, one, two, dirty_submodule,
+                             &left, &right, &merge_bases);
 
        /* We need a valid left and right commit to display a difference */
        if (!(left || is_null_oid(one)) ||
@@ -677,16 +606,16 @@ void show_submodule_inline_diff(FILE *f, const char *path,
        if (right)
                new = two;
 
-       fflush(f);
        cp.git_cmd = 1;
        cp.dir = path;
-       cp.out = dup(fileno(f));
+       cp.out = -1;
        cp.no_stdin = 1;
 
        /* TODO: other options may need to be passed here. */
        argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
+       argv_array_pushf(&cp.args, "--color=%s", want_color(o->use_color) ?
+                        "always" : "never");
 
-       argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix);
        if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
                argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
                                 o->b_prefix, path);
@@ -709,11 +638,17 @@ void show_submodule_inline_diff(FILE *f, const char *path,
                argv_array_push(&cp.args, oid_to_hex(new));
 
        prepare_submodule_repo_env(&cp.env_array);
-       if (run_command(&cp))
-               fprintf(f, "(diff failed)\n");
+       if (start_command(&cp))
+               diff_emit_submodule_error(o, "(diff failed)\n");
+
+       while (strbuf_getwholeline_fd(&sb, cp.out, '\n') != EOF)
+               diff_emit_submodule_pipethrough(o, sb.buf, sb.len);
+
+       if (finish_command(&cp))
+               diff_emit_submodule_error(o, "(diff failed)\n");
 
 done:
-       strbuf_release(&submodule_dir);
+       strbuf_release(&sb);
        if (merge_bases)
                free_commit_list(merge_bases);
        if (left)
@@ -839,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'.
@@ -867,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
@@ -886,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)
@@ -1012,7 +964,8 @@ static int push_submodule(const char *path,
  * Perform a check in the submodule to see if the remote and refspec work.
  * Die if the submodule can't be pushed.
  */
-static void submodule_push_check(const char *path, const struct remote *remote,
+static void submodule_push_check(const char *path, const char *head,
+                                const struct remote *remote,
                                 const char **refspec, int refspec_nr)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
@@ -1020,6 +973,7 @@ static void submodule_push_check(const char *path, const struct remote *remote,
 
        argv_array_push(&cp.args, "submodule--helper");
        argv_array_push(&cp.args, "push-check");
+       argv_array_push(&cp.args, head);
        argv_array_push(&cp.args, remote->name);
 
        for (i = 0; i < refspec_nr; i++)
@@ -1058,10 +1012,20 @@ int push_unpushed_submodules(struct oid_array *commits,
         * won't be propagated due to the remote being unconfigured (e.g. a URL
         * instead of a remote name).
         */
-       if (remote->origin != REMOTE_UNCONFIGURED)
+       if (remote->origin != REMOTE_UNCONFIGURED) {
+               char *head;
+               struct object_id head_oid;
+
+               head = resolve_refdup("HEAD", 0, head_oid.hash, 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,
-                                            remote, refspec, refspec_nr);
+                                            head, remote,
+                                            refspec, refspec_nr);
+               free(head);
+       }
 
        /* Actually push the submodules */
        for (i = 0; i < needs_pushing.nr; i++) {
@@ -1142,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;
@@ -1194,14 +1157,24 @@ static int get_next_submodule(struct child_process *cp,
 
                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";
@@ -1678,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 */
@@ -2039,7 +2014,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;