summaryrefslogtreecommitdiff
path: root/submodule.c
diff options
context:
space:
mode:
authorStefan Beller <sbeller@google.com>2018-05-15 20:00:28 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-05-16 01:08:43 (GMT)
commit18cfc0886617e28fb6d29d579bec0ffcdb439196 (patch)
tree70f603f53147672e2a41e3dd4f82f66d3bb80e58 /submodule.c
parentccdcbd54c4475c2238b310f7113ab3075b5abc9c (diff)
downloadgit-18cfc0886617e28fb6d29d579bec0ffcdb439196.zip
git-18cfc0886617e28fb6d29d579bec0ffcdb439196.tar.gz
git-18cfc0886617e28fb6d29d579bec0ffcdb439196.tar.bz2
submodule.c: move submodule merging to merge-recursive.c
In a later patch we want to improve submodule merging by using the output() function in merge-recursive.c for submodule merges to deliver a consistent UI to users. To do so we could either make the output() function globally available so we can use it in submodule.c#merge_submodule(), or we could integrate the submodule merging into the merging code. Choose the later as we generally want to move submodules closer into the core. Therefore we move any function related to merging submodules (merge_submodule(), find_first_merges() and print_commit) to merge-recursive.c. We'll keep add_submodule_odb() in submodule.c as it is used by other submodule functions. While at it, add a TODO note that we do not really like the function add_submodule_odb(). This commit is best viewed with --color-moved. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'submodule.c')
-rw-r--r--submodule.c168
1 files changed, 2 insertions, 166 deletions
diff --git a/submodule.c b/submodule.c
index 74d35b2..654089b 100644
--- a/submodule.c
+++ b/submodule.c
@@ -153,7 +153,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;
@@ -1701,171 +1702,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.