Merge branch 'sm/show-superproject-while-conflicted' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 Nov 2018 13:57:48 +0000 (22:57 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 21 Nov 2018 13:57:48 +0000 (22:57 +0900)
A corner-case bugfix.

* sm/show-superproject-while-conflicted:
rev-parse: --show-superproject-working-tree should work during a merge

1  2 
submodule.c
diff --combined submodule.c
index 4a5212bdfb4ab9ce5aac4a4c4460fbc9c9ecff38,540e9df48566a878bcbe0cf23137d16b66f958df..f27f14e86817607f7d11e376431d1b2864939aab
@@@ -21,7 -21,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;
@@@ -65,7 -64,8 +65,7 @@@ int is_staging_gitmodules_ok(struct ind
        if ((pos >= 0) && (pos < istate->cache_nr)) {
                struct stat st;
                if (lstat(GITMODULES_FILE, &st) == 0 &&
 -                  ie_match_stat(istate, istate->cache[pos], &st,
 -                                CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED)
 +                  ie_match_stat(istate, istate->cache[pos], &st, 0) & DATA_CHANGED)
                        return 0;
        }
  
@@@ -92,10 -92,10 +92,10 @@@ int update_path_in_gitmodules(const cha
        if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
                return -1;
  
 -      if (is_gitmodules_unmerged(&the_index))
 +      if (is_gitmodules_unmerged(the_repository->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,10 -126,10 +126,10 @@@ int remove_path_from_gitmodules(const c
        if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
                return -1;
  
 -      if (is_gitmodules_unmerged(&the_index))
 +      if (is_gitmodules_unmerged(the_repository->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;
@@@ -152,8 -152,7 +152,8 @@@ void stage_updated_gitmodules(struct in
                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;
@@@ -174,8 -173,7 +174,8 @@@ done
  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;
  
                if (ignore)
                        handle_ignore_submodules_arg(diffopt, ignore);
 -              else if (is_gitmodules_unmerged(&the_index))
 +              else if (is_gitmodules_unmerged(the_repository->index))
                        diffopt->flags.ignore_submodules = 1;
        }
  }
@@@ -231,7 -229,7 +231,7 @@@ int is_submodule_active(struct reposito
        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)
                }
  
                parse_pathspec(&ps, 0, 0, NULL, args.argv);
 -              ret = match_pathspec(&ps, path, strlen(path), 0, NULL, 1);
 +              ret = match_pathspec(repo->index, &ps, path, strlen(path), 0, NULL, 1);
  
                argv_array_clear(&args);
                clear_pathspec(&ps);
@@@ -516,8 -514,8 +516,8 @@@ static void show_submodule_header(struc
         * 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
  
  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
@@@ -675,7 -673,7 +675,7 @@@ const struct submodule *submodule_from_
        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,
@@@ -732,21 -730,18 +732,21 @@@ static void collect_changed_submodules_
                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);
 +                      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;
                        }
                }
@@@ -822,7 -817,7 +822,7 @@@ static int check_has_commit(const struc
  {
        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:
@@@ -949,7 -944,7 +949,7 @@@ int find_unpushed_submodules(struct oid
                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
  
  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)
  {
                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);
   */
  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;
        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;
  
  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)
  {
  
                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);
        }
  
        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;
@@@ -1116,7 -1112,7 +1116,7 @@@ static void calculate_changed_submodule
        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 */
                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
@@@ -1165,15 -1161,13 +1165,15 @@@ int submodule_touches_in_range(struct o
        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;
@@@ -1239,7 -1233,7 +1239,7 @@@ static int get_next_submodule(struct ch
                if (!S_ISGITLINK(ce->ce_mode))
                        continue;
  
 -              submodule = submodule_from_cache(spf->r, &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) {
@@@ -1403,7 -1397,7 +1403,7 @@@ unsigned is_submodule_modified(const ch
                    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')
@@@ -1572,7 -1566,7 +1572,7 @@@ static void submodule_reset_index(cons
                                   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");
@@@ -1609,10 -1603,10 +1609,10 @@@ int submodule_move_head(const char *pat
        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_head && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) {
                /* Check if the submodule has a dirty index. */
                } 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 */
                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);
                }
        }
                argv_array_push(&cp.args, "-m");
  
        if (!(flags & SUBMODULE_MOVE_HEAD_FORCE))
 -              argv_array_push(&cp.args, old_head ? old_head : EMPTY_TREE_SHA1_HEX);
 +              argv_array_push(&cp.args, old_head ? old_head : empty_tree_oid_hex());
  
 -      argv_array_push(&cp.args, new_head ? new_head : EMPTY_TREE_SHA1_HEX);
 +      argv_array_push(&cp.args, new_head ? new_head : empty_tree_oid_hex());
  
        if (run_command(&cp)) {
 -              ret = -1;
 +              ret = error(_("Submodule '%s' could not be updated."), path);
                goto out;
        }
  
        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.
@@@ -1726,7 -1885,7 +1726,7 @@@ static void relocate_single_git_dir_int
  
        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);
  
@@@ -1782,11 -1941,11 +1782,11 @@@ void absorb_git_dir_into_superproject(c
                * 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);
                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);
@@@ -1879,11 -2038,11 +1879,11 @@@ const char *get_superproject_working_tr
                 * We're only interested in the name after the tab.
                 */
                super_sub = strchr(sb.buf, '\t') + 1;
-               super_sub_len = sb.buf + sb.len - super_sub - 1;
+               super_sub_len = strlen(super_sub);
  
                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';
@@@ -1928,7 -2087,7 +1928,7 @@@ int submodule_to_gitdir(struct strbuf *
                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;