From: Junio C Hamano Date: Wed, 21 Nov 2018 13:57:48 +0000 (+0900) Subject: Merge branch 'sm/show-superproject-while-conflicted' into maint X-Git-Tag: v2.19.2~50 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/9674e7a333150d4f4a4752b25b4066bcd0406ddf?hp=-c Merge branch 'sm/show-superproject-while-conflicted' into maint A corner-case bugfix. * sm/show-superproject-while-conflicted: rev-parse: --show-superproject-working-tree should work during a merge --- 9674e7a333150d4f4a4752b25b4066bcd0406ddf diff --combined submodule.c index 4a5212bdfb,540e9df485..f27f14e868 --- a/submodule.c +++ b/submodule.c @@@ -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; @@@ -187,7 -185,7 +187,7 @@@ 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) @@@ -257,7 -255,7 +257,7 @@@ } 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 @@@ -542,9 -540,9 +542,9 @@@ 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 @@@ -970,7 -965,7 +970,7 @@@ 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) { @@@ -993,8 -988,8 +993,8 @@@ 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); @@@ -1015,7 -1010,7 +1015,7 @@@ */ 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; @@@ -1025,8 -1020,8 +1025,8 @@@ 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; @@@ -1045,7 -1040,7 +1045,7 @@@ 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) { @@@ -1071,7 -1066,8 +1071,7 @@@ 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); } @@@ -1079,7 -1075,7 +1079,7 @@@ 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 */ @@@ -1137,7 -1133,7 +1137,7 @@@ 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. */ @@@ -1628,7 -1622,7 +1628,7 @@@ } 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 */ @@@ -1638,7 -1632,7 +1638,7 @@@ 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); } } @@@ -1664,12 -1658,12 +1664,12 @@@ 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; } @@@ -1704,6 -1698,171 +1704,6 @@@ 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); @@@ -1805,7 -1964,7 +1805,7 @@@ 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;