summaryrefslogtreecommitdiff
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
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>
-rw-r--r--merge-recursive.c166
-rw-r--r--submodule.c168
-rw-r--r--submodule.h6
3 files changed, 170 insertions, 170 deletions
diff --git a/merge-recursive.c b/merge-recursive.c
index 0c0d486..700ba15 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -23,6 +23,7 @@
#include "merge-recursive.h"
#include "dir.h"
#include "submodule.h"
+#include "revision.h"
struct path_hashmap_entry {
struct hashmap_entry e;
@@ -977,6 +978,171 @@ static int merge_3way(struct merge_options *o,
return merge_status;
}
+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);
+
+static 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;
+}
+
static int merge_file_1(struct merge_options *o,
const struct diff_filespec *one,
const struct diff_filespec *a,
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.
diff --git a/submodule.h b/submodule.h
index e5526f6..b96689a 100644
--- a/submodule.h
+++ b/submodule.h
@@ -89,10 +89,8 @@ extern int submodule_uses_gitfile(const char *path);
#define SUBMODULE_REMOVAL_IGNORE_UNTRACKED (1<<1)
#define SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED (1<<2)
extern int bad_to_remove_submodule(const char *path, unsigned flags);
-extern 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);
+
+int add_submodule_odb(const char *path);
/* Checks if there are submodule changes in a..b. */
extern int submodule_touches_in_range(struct object_id *a,