|
23 | 23 | #include "merge-recursive.h"
|
24 | 24 | #include "dir.h"
|
25 | 25 | #include "submodule.h"
|
| 26 | +#include "revision.h" |
26 | 27 |
|
27 | 28 | struct path_hashmap_entry {
|
28 | 29 | struct hashmap_entry e;
|
@@ -1082,6 +1083,185 @@ static int merge_3way(struct merge_options *o,
|
1082 | 1083 | return merge_status;
|
1083 | 1084 | }
|
1084 | 1085 |
|
| 1086 | +static int find_first_merges(struct object_array *result, const char *path, |
| 1087 | + struct commit *a, struct commit *b) |
| 1088 | +{ |
| 1089 | + int i, j; |
| 1090 | + struct object_array merges = OBJECT_ARRAY_INIT; |
| 1091 | + struct commit *commit; |
| 1092 | + int contains_another; |
| 1093 | + |
| 1094 | + char merged_revision[42]; |
| 1095 | + const char *rev_args[] = { "rev-list", "--merges", "--ancestry-path", |
| 1096 | + "--all", merged_revision, NULL }; |
| 1097 | + struct rev_info revs; |
| 1098 | + struct setup_revision_opt rev_opts; |
| 1099 | + |
| 1100 | + memset(result, 0, sizeof(struct object_array)); |
| 1101 | + memset(&rev_opts, 0, sizeof(rev_opts)); |
| 1102 | + |
| 1103 | + /* get all revisions that merge commit a */ |
| 1104 | + xsnprintf(merged_revision, sizeof(merged_revision), "^%s", |
| 1105 | + oid_to_hex(&a->object.oid)); |
| 1106 | + init_revisions(&revs, NULL); |
| 1107 | + rev_opts.submodule = path; |
| 1108 | + /* FIXME: can't handle linked worktrees in submodules yet */ |
| 1109 | + revs.single_worktree = path != NULL; |
| 1110 | + setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts); |
| 1111 | + |
| 1112 | + /* save all revisions from the above list that contain b */ |
| 1113 | + if (prepare_revision_walk(&revs)) |
| 1114 | + die("revision walk setup failed"); |
| 1115 | + while ((commit = get_revision(&revs)) != NULL) { |
| 1116 | + struct object *o = &(commit->object); |
| 1117 | + if (in_merge_bases(b, commit)) |
| 1118 | + add_object_array(o, NULL, &merges); |
| 1119 | + } |
| 1120 | + reset_revision_walk(); |
| 1121 | + |
| 1122 | + /* Now we've got all merges that contain a and b. Prune all |
| 1123 | + * merges that contain another found merge and save them in |
| 1124 | + * result. |
| 1125 | + */ |
| 1126 | + for (i = 0; i < merges.nr; i++) { |
| 1127 | + struct commit *m1 = (struct commit *) merges.objects[i].item; |
| 1128 | + |
| 1129 | + contains_another = 0; |
| 1130 | + for (j = 0; j < merges.nr; j++) { |
| 1131 | + struct commit *m2 = (struct commit *) merges.objects[j].item; |
| 1132 | + if (i != j && in_merge_bases(m2, m1)) { |
| 1133 | + contains_another = 1; |
| 1134 | + break; |
| 1135 | + } |
| 1136 | + } |
| 1137 | + |
| 1138 | + if (!contains_another) |
| 1139 | + add_object_array(merges.objects[i].item, NULL, result); |
| 1140 | + } |
| 1141 | + |
| 1142 | + object_array_clear(&merges); |
| 1143 | + return result->nr; |
| 1144 | +} |
| 1145 | + |
| 1146 | +static void print_commit(struct commit *commit) |
| 1147 | +{ |
| 1148 | + struct strbuf sb = STRBUF_INIT; |
| 1149 | + struct pretty_print_context ctx = {0}; |
| 1150 | + ctx.date_mode.type = DATE_NORMAL; |
| 1151 | + format_commit_message(commit, " %h: %m %s", &sb, &ctx); |
| 1152 | + fprintf(stderr, "%s\n", sb.buf); |
| 1153 | + strbuf_release(&sb); |
| 1154 | +} |
| 1155 | + |
| 1156 | +static int merge_submodule(struct merge_options *o, |
| 1157 | + struct object_id *result, const char *path, |
| 1158 | + const struct object_id *base, const struct object_id *a, |
| 1159 | + const struct object_id *b) |
| 1160 | +{ |
| 1161 | + struct commit *commit_base, *commit_a, *commit_b; |
| 1162 | + int parent_count; |
| 1163 | + struct object_array merges; |
| 1164 | + |
| 1165 | + int i; |
| 1166 | + int search = !o->call_depth; |
| 1167 | + |
| 1168 | + /* store a in result in case we fail */ |
| 1169 | + oidcpy(result, a); |
| 1170 | + |
| 1171 | + /* we can not handle deletion conflicts */ |
| 1172 | + if (is_null_oid(base)) |
| 1173 | + return 0; |
| 1174 | + if (is_null_oid(a)) |
| 1175 | + return 0; |
| 1176 | + if (is_null_oid(b)) |
| 1177 | + return 0; |
| 1178 | + |
| 1179 | + if (add_submodule_odb(path)) { |
| 1180 | + output(o, 1, _("Failed to merge submodule %s (not checked out)"), path); |
| 1181 | + return 0; |
| 1182 | + } |
| 1183 | + |
| 1184 | + if (!(commit_base = lookup_commit_reference(base)) || |
| 1185 | + !(commit_a = lookup_commit_reference(a)) || |
| 1186 | + !(commit_b = lookup_commit_reference(b))) { |
| 1187 | + output(o, 1, _("Failed to merge submodule %s (commits not present)"), path); |
| 1188 | + return 0; |
| 1189 | + } |
| 1190 | + |
| 1191 | + /* check whether both changes are forward */ |
| 1192 | + if (!in_merge_bases(commit_base, commit_a) || |
| 1193 | + !in_merge_bases(commit_base, commit_b)) { |
| 1194 | + output(o, 1, _("Failed to merge submodule %s (commits don't follow merge-base)"), path); |
| 1195 | + return 0; |
| 1196 | + } |
| 1197 | + |
| 1198 | + /* Case #1: a is contained in b or vice versa */ |
| 1199 | + if (in_merge_bases(commit_a, commit_b)) { |
| 1200 | + oidcpy(result, b); |
| 1201 | + if (show(o, 3)) { |
| 1202 | + output(o, 3, _("Fast-forwarding submodule %s to the following commit:"), path); |
| 1203 | + output_commit_title(o, commit_b); |
| 1204 | + } else if (show(o, 2)) |
| 1205 | + output(o, 2, _("Fast-forwarding submodule %s to %s"), path, oid_to_hex(b)); |
| 1206 | + else |
| 1207 | + ; /* no output */ |
| 1208 | + |
| 1209 | + return 1; |
| 1210 | + } |
| 1211 | + if (in_merge_bases(commit_b, commit_a)) { |
| 1212 | + oidcpy(result, a); |
| 1213 | + if (show(o, 3)) { |
| 1214 | + output(o, 3, _("Fast-forwarding submodule %s to the following commit:"), path); |
| 1215 | + output_commit_title(o, commit_a); |
| 1216 | + } else if (show(o, 2)) |
| 1217 | + output(o, 2, _("Fast-forwarding submodule %s to %s"), path, oid_to_hex(a)); |
| 1218 | + else |
| 1219 | + ; /* no output */ |
| 1220 | + |
| 1221 | + return 1; |
| 1222 | + } |
| 1223 | + |
| 1224 | + /* |
| 1225 | + * Case #2: There are one or more merges that contain a and b in |
| 1226 | + * the submodule. If there is only one, then present it as a |
| 1227 | + * suggestion to the user, but leave it marked unmerged so the |
| 1228 | + * user needs to confirm the resolution. |
| 1229 | + */ |
| 1230 | + |
| 1231 | + /* Skip the search if makes no sense to the calling context. */ |
| 1232 | + if (!search) |
| 1233 | + return 0; |
| 1234 | + |
| 1235 | + /* find commit which merges them */ |
| 1236 | + parent_count = find_first_merges(&merges, path, commit_a, commit_b); |
| 1237 | + switch (parent_count) { |
| 1238 | + case 0: |
| 1239 | + output(o, 1, _("Failed to merge submodule %s (merge following commits not found)"), path); |
| 1240 | + break; |
| 1241 | + |
| 1242 | + case 1: |
| 1243 | + output(o, 1, _("Failed to merge submodule %s (not fast-forward)"), path); |
| 1244 | + output(o, 2, _("Found a possible merge resolution for the submodule:\n")); |
| 1245 | + print_commit((struct commit *) merges.objects[0].item); |
| 1246 | + output(o, 2, _( |
| 1247 | + "If this is correct simply add it to the index " |
| 1248 | + "for example\n" |
| 1249 | + "by using:\n\n" |
| 1250 | + " git update-index --cacheinfo 160000 %s \"%s\"\n\n" |
| 1251 | + "which will accept this suggestion.\n"), |
| 1252 | + oid_to_hex(&merges.objects[0].item->oid), path); |
| 1253 | + break; |
| 1254 | + |
| 1255 | + default: |
| 1256 | + output(o, 1, _("Failed to merge submodule %s (multiple merges found)"), path); |
| 1257 | + for (i = 0; i < merges.nr; i++) |
| 1258 | + print_commit((struct commit *) merges.objects[i].item); |
| 1259 | + } |
| 1260 | + |
| 1261 | + object_array_clear(&merges); |
| 1262 | + return 0; |
| 1263 | +} |
| 1264 | + |
1085 | 1265 | static int merge_file_1(struct merge_options *o,
|
1086 | 1266 | const struct diff_filespec *one,
|
1087 | 1267 | const struct diff_filespec *a,
|
@@ -1145,12 +1325,11 @@ static int merge_file_1(struct merge_options *o,
|
1145 | 1325 | return ret;
|
1146 | 1326 | result->clean = (merge_status == 0);
|
1147 | 1327 | } else if (S_ISGITLINK(a->mode)) {
|
1148 |
| - result->clean = merge_submodule(&result->oid, |
| 1328 | + result->clean = merge_submodule(o, &result->oid, |
1149 | 1329 | one->path,
|
1150 | 1330 | &one->oid,
|
1151 | 1331 | &a->oid,
|
1152 |
| - &b->oid, |
1153 |
| - !o->call_depth); |
| 1332 | + &b->oid); |
1154 | 1333 | } else if (S_ISLNK(a->mode)) {
|
1155 | 1334 | switch (o->recursive_variant) {
|
1156 | 1335 | case MERGE_RECURSIVE_NORMAL:
|
|
0 commit comments