test-reach: test reduce_heads
[gitweb.git] / submodule.c
index 47d005797e3951ac1878d9bdb1ac8de99b392464..6650ed7aa02b2b657929c8868d05b83583c0093a 100644 (file)
@@ -22,6 +22,7 @@
 #include "worktree.h"
 #include "parse-options.h"
 #include "object-store.h"
+#include "commit-reach.h"
 
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
 static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP;
@@ -153,7 +154,8 @@ void stage_updated_gitmodules(struct index_state *istate)
                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;
@@ -516,8 +518,8 @@ static void show_submodule_header(struct diff_options *o, const char *path,
         * Attempt to lookup the commit references, and determine if this is
         * a fast forward or fast backwards update.
         */
-       *left = lookup_commit_reference(one);
-       *right = lookup_commit_reference(two);
+       *left = lookup_commit_reference(the_repository, one);
+       *right = lookup_commit_reference(the_repository, two);
 
        /*
         * Warn about missing commits in the submodule project, but only if
@@ -739,12 +741,14 @@ static void collect_changed_submodules_cb(struct diff_queue_struct *q,
                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 (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 "
                                        "the same. Skipping it.",
-                                       oid_to_hex(commit_oid), name);
+                                       oid_to_hex(commit_oid), p->two->path);
                                name = NULL;
                        }
                }
@@ -1168,8 +1172,10 @@ int submodule_touches_in_range(struct object_id *excl_oid,
 
        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;
@@ -1700,171 +1706,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.